草庐IT

c# - 将 set 访问器添加到类中的属性,该类派生自只有一个 get 访问器的抽象类

coder 2024-05-20 原文

我有一个抽象类, AbsClass 实现一个接口(interface), IClass . IClass 有几个属性只有 Get 访问器。 AbsClass 实现 的属性IClass 作为要在派生自 的类中定义的抽象属性AbsClass .

所以所有派生自 的类AbsClass 还需要满足 IClass 通过与 Get 访问器具有相同的属性。但是,在某些情况下,我希望能够向来自 的属性添加 set 访问器。 IClass .然而,如果我尝试覆盖 中的抽象属性AbsClass 使用 set accessor 我收到此错误

ConcClassA.Bottom.Set 无法覆盖,因为 AbsClass.Bottom 没有可覆盖的 set 访问器

ConcClassA 以下。

如果我有一个仅实现 的类IClass 接口(interface),但不是从 AbsClass 继承然后我可以添加一个没有问题的 set 访问器。见 ConcClassB 以下。

我可以在 AbsClass 的每个派生中实现 IClass,而不是直接为 AbsClass 实现。然而我从我的设计中知道,每个 AbsClass 也需要是一个 IClass,所以我宁愿在层次结构中指定更高的位置。

public interface IClass
{
    double Top
    {
        get;
    }
    double Bottom
    {
        get;
    }
}

abstract class AbsClass:IClass
{
    public abstract double Top
    {
        get;
    }

    public abstract double Bottom
    {
        get;
    }
}



class ConcClassA : AbsClass
{
    public override double Top
    {
        get { return 1; }
    }

    public override double Bottom
    {
        get { return 1; }

        //adding a Set accessor causes error:
        //ConcClassA.Bottom.Set cannot override because AbsClass.Bottom does not have an overridable set accessor

        //set { }
    }

}

class ConcClassB : IClass
{
    public double Top
    {
        get { return 1; }
        //added a set accessor to an interface does not cause problem
        set { }
    }
    public double Bottom
    {
        get { return 1; }
    }
}

更新

所以我认为如果我准确地解释我想要做的事情而不是使用抽象的例子,这会更有意义。我在一家建筑公司工作,这些是与建筑设计项目相关的业务对象。

我有一个抽象类 RhNodeBuilding 代表项目中的一种建筑类型。 中定义了一些通用功能,例如拥有楼层的能力。 RhNodeBuilding . RhNodeBuilding 还从另一个抽象类继承,使其成为更大的项目树结构的一部分。

RhNodeBuilding 从接口(interface)实现 IBuilding 它定义了所有建筑物都应该能够提供的许多只读属性,例如 TopElevation , 底部海拔 , 高度 , 楼层数 等等。请记住,还有其他建筑类型并非源自 RhNodeBuilding ,但仍需实现 IBuilding .

现在我有两种派生自 的类型。 RhNodeBuilding :大众建筑 足印建筑 . 大众建筑 由用户创建的 3D 形状定义。该形状具有 TopElevation 和一个 底部海拔 应该可以通过相应的属性访问,但是您不能通过更改属性来编辑 3D 体积。

足印建筑另一方面,由闭合曲线和挤出该曲线的高度范围定义。因此,该类不仅应该能够返回当前的高度,而且还应该能够更改这些高度以重新定义高度范围。

所以总结一下。所有建筑物( IBuildings )都需要能够返回 TopElevation 底部海拔 ,但并非所有建筑物都应允许 TopElevation 底部海拔 要直接设置。全部 RhNodeBuildings IBuildings ,以及派生自 的类RhNodeBuilding 可能需要也可能不需要直接设置 TopElevation 底部海拔 .
public interface IBuilding
{
    double Top
    {
        get;
    }
    double Bottom
    {
        get;
    }
}

abstract class RhNodeBuilding:IBuilding
{
    public abstract double Top
    {
        get;
    }

    public abstract double Bottom
    {
        get;
    }
}



class MassBuilding: AbsClass
{

   //mass building only returns Top and Bottom properties so it works fine
    public override double Bottom
    {
        get { return 1; }
    }

    public override double Top
    {
        get { return 1; }
    }

}


class FootPrintBuilding: AbsClass
{
    //Top and Bottom of FootPrintBuilding can both be retrieved and set
    public override double Top
    {
        get { return 1; }
        //adding a Set accessor causes error:
        //cannot override because RhNodeBuilding.Top does not have an overridable set accessor

        //set { }
    }

    public override double Bottom
    {
        get { return 1; }

        //adding a Set accessor causes error:
        //cannot override because RhNodeBuilding.Bottom does not have an overridable set accessor

        //set { }
    }

}

现在看来最好的选择是没有 RhNodeBuilding 实现 IBuilding ,而是拥有从 派生的每个类RhNodeBuilding 实现 IBuilding。这样我就可以从 定义属性IBuilding 直接而不是作为覆盖。
abstract class AltRhNodeBuilding
{
    public abstract double Top
    {
        get;
    }
}


class AltFootPrintBuilding: IClass
{
    public override double Top
    {
        get { return 1; }

       //Can't add set access to overridden abstract property
        set { }
    }

    //No problem adding set accessor to interface property
    public double Bottom
    {
        get { return 1; }
        set {  }
    }
}

最佳答案

这是因为属性不是真正虚拟的 - 它们的访问器方法是。因此,您不能覆盖 set如果基类中没有。

您可以做的是覆盖和隐藏基类实现,并提供您自己的新读/写属性。如果不在层次结构中引入额外的类,我不知道有什么方法可以做到这一点:

class AbsClassB : AbsClass
{
    public override double Top { get { return ((ConcClassB)this).Top } }
    public override double Bottom { get { return ((ConcClassB)this).Bottom } }
}


class ConcClassB :  AbsClassB
{
    new public double Top
    {
        get { ... }
        set { ... }
    }

    new public double Bottom
    {
        get { ... }
        set { ... }
    }
}

更好的想法是在 AbsClass 中定义一个 protected 虚拟方法。 ,并实现 Top.getBottom.get就那个方法而言。然后您可以直接在 ConcClassB 中覆盖该方法,并隐藏属性,无需额外的类:
abstract class AbsClass : IClass
{
    public double Top
    {
        get { return GetTop(); }
    }

    public double Bottom
    {
        get { return GetBottom(); }
    }

    protected abstract double GetTop();

    protected abstract double GetBottom();
}

class ConcClassB :  AbsClass
{
    new public double Top
    {
        get { ... }
        set { ... }
    }

    new public double Bottom
    {
        get { ... }
        set { ... }
    }

    protected override double GetTop()
    {
        return Top;
    }

    protected override double GetBottom()
    {
        return Bottom;
    }
}

关于c# - 将 set 访问器添加到类中的属性,该类派生自只有一个 get 访问器的抽象类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1169571/

有关c# - 将 set 访问器添加到类中的属性,该类派生自只有一个 get 访问器的抽象类的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  3. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  4. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  5. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  6. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  7. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  8. ruby - Sinatra set cache_control to static files in public folder编译错误 - 2

    我不知道为什么,但是当我设置这个设置时它无法编译设置:static_cache_control,[:public,:max_age=>300]这是我得到的syntaxerror,unexpectedtASSOC,expecting']'(SyntaxError)set:static_cache_control,[:public,:max_age=>300]^我只想将“过期”header设置为css、javaascript和图像文件。谢谢。 最佳答案 我猜您使用的是Ruby1.8.7。Sinatra文档中显示的语法似乎是在Ruby1.

  9. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  10. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

随机推荐