【问题标题】:Adding setters to properties in overrides将设置器添加到覆盖中的属性
【发布时间】:2011-08-28 20:06:43
【问题描述】:

为什么允许在实现接口时更改属性中 getter 或 setter 的可见性和存在?

interface IFoo
{
    string Bar { get; }
}

class RealFoo : IFoo
{
    public RealFoo(string bar)
    {
        this.Bar = bar;
    }

    public string Bar { get; private set; }
}

class StubFoo : IFoo
{
    public string Bar { get; set; }
}

...在实现抽象类时这样做不合法吗?

abstract class AbstractFoo : IFoo
{
    public abstract string Bar { get; }
}

class RealFoo : AbstractFoo
{
    public RealFoo(string bar)
    {
        this.Bar = bar;
    }

    // Cannot override because 'Bar' does not have an overridable set accessor
    public override string Bar { get; private set; }
}

【问题讨论】:

  • 在您的示例中,您正在向接口实现添加代码,因为没有设置器,但您正在更改中的可见性抽象类实现。所以就不一样了。
  • @jv42 由于设置器是 private,因此在实现中没有更改可见性。该限制是任意且愚蠢的......也可以指定 C# 以允许覆盖仅在它们不是私有时应用于获取或设置。或者它可以允许public string Bar { override get; private set; }
  • @JimBalter 我同意可能存在改变访问者可见性的机制。您可能想查看 C# 6 中的新内容,我已经看到了一些有趣的属性新内容。
  • @jv42 我已经知道 C# 6 中会发生什么,但它不存在。关键是您的评论错误
  • @JimBalter 好吧,那我们就意见不合了。

标签: c# properties abstract


【解决方案1】:

接口声明了类必须具有的公共属性(它只是一个契约)。这意味着您需要拥有这些属性,但可以添加它们。

抽象类声明了这些属性的实际结构。因此,如果您在抽象基础中没有设置器,则无法在实现中添加它。
当您编写 override 修饰符时,它会在基类中查找要覆盖的内容。

【讨论】:

    【解决方案2】:

    抽象类是不能实例化但必须继承的类。抽象类可以完全实现,但更常见的是部分实现或根本不实现,从而封装了继承类的通用功能。

    相比之下,接口是一组完全抽象的成员,可以被认为是定义行为契约。接口的实现完全留给开发人员。

    取自 MSDN http://msdn.microsoft.com/en-us/library/scsyfw1d(v=VS.71).aspx

    【讨论】:

    • 好的,这意味着在类层次结构中添加抽象基类将强制您在某些派生类中添加空/抛出异常的 setter 实现。不是最优雅的行为。
    • 这个“答案”没有触及实际提出的问题。
    【解决方案3】:

    根据 C# 规范

    用于实现的访问器 接口可能没有 访问器修饰符。如果只有一个 访问器用于实现一个 接口,其他访问者可能是 用访问器修饰符声明:

    public interface I
    {
      string Prop { get; }
    }
    public class C: I
    {
      public Prop {
      get { return "April"; }     // Must not have a modifier here
            internal set {...}    // Ok, because I.Prop has no set accessor
      }
    }
    

    这意味着可以在实现接口的类上修改访问权限。但是,抽象类声明了一个实现,您不能使用派生类更改它。

    【讨论】:

    • abstract 属性没有实现。 “抽象类声明一个实现”是什么意思?抽象类任意限制实现,接口不任意限制实现?
    • 是的,抽象类可以有实现。抽象类可能缺乏实现或可能未完全实现。抽象类只能用于派生其他类。
    • “抽象类可以有实现”——@binki 说抽象 properties 没有实现。你的回复没有回应他的评论。 C# 没有充分的理由不允许 public string Bar { override get; private set; } 之类的东西
    【解决方案4】:

    如果您将 getter 和 setter 视为它们最终成为的方法,可能会更清楚。

    在你定义这个接口的情况下:

    interface IFoo
    {
        string GetBar();
    }
    

    可以理解为“所有实现这个接口的类必须包含这个方法”。 你的两个班级都这样做:

    class RealFoo : IFoo
    {
        public string GetBar();
        private void SetBar(string value);
    }
    

    他们也实现了 SetBar(),但这并不重要;他们已经履行了接口定义的契约并且是有效的。

    另一方面,抽象类是这样的:

    abstract class AbstractFoo : IFoo
    {
        public abstract string GetBar();
    }
    

    这意味着所有子类都必须为 GetBar() 提供方法体

    你制作的课程是这样的:

    class RealFoo : AbstractFoo
    {
        public override string GetBar();
        public override void SetBar(string value);
    }
    

    通过将 override 修饰符放在 SetBar 方法前面,编译器期望在基类中找到抽象或虚拟版本。你没有那个所以编译失败。

    【讨论】:

    • 这意味着属性实际上只是 setter 和 getter 的快捷方式,并没有假设好的 oo 设计原则。
    • 所以你是在间接说 C# 必须添加像 public string Bar { override get; set; } 这样的语法,然后我们在实现抽象属性的方式上就不会受到任意限制。这实际上是有道理的。
    • @binki 这确实有道理,这就是为什么这些答案没有,而且限制是任意的,而且设计很差。 C# 不必“添加语法”,它可以简单地采用 OP 提供的语法并对其进行智能处理,而不是要求我们显式提供支持变量。
    猜你喜欢
    • 1970-01-01
    • 2019-07-28
    • 1970-01-01
    • 2015-11-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-29
    • 2014-03-11
    • 2012-03-06
    相关资源
    最近更新 更多