为什么不可能覆盖仅getter的属性并添加setter?[关闭]


141

为什么不允许以下C#代码:

public abstract class BaseClass
{
    public abstract int Bar { get;}
}

public class ConcreteClass : BaseClass
{
    public override int Bar
    {
        get { return 0; }
        set {}
    }
}

CS0546'ConcreteClass.Bar.set':无法覆盖,因为'BaseClass.Bar'没有可覆盖的集合访问器


9
StackOverflow代表Microsoft回答问题的能力有限。考虑改写您的问题。
Jay Bazuzi

1
顺便说一句,.net中此烦人行为的一种简单补救方法是拥有一个非虚拟的只读属性Foo,该属性除了包装受保护的抽象GetFoo方法外什么也不做。抽象派生类型可以用非虚拟读写属性来遮盖该属性,该属性除了将上述GetFoo方法与抽象SetFoo方法一起包装外什么也没有做。一个具体的派生类型可以完成上述工作,但提供了GetFoo和的定义SetFoo
2012年

1
只是为了增加燃料,C ++ / CLI确实允许这样做。
ymett '16

1
已经提出了在覆盖属性时添加访问器的功能,作为对C#的未来版本的更改(github.com/dotnet/roslyn/issues/9482)。
布兰登·邦德斯

1
坦率地说,当需要扩展使用以下模式的现有库类型时,通常会提出此问题:只读基类,派生可变类。由于该库已经使用了错误的模式(例如WPF),因此需要解决该错误的模式。讲解并不能挽救一天结束时必须执行的解决方法。
rwong

Answers:


-4

因为Baseclass的作者已明确声明Bar必须是一个只读属性。推导打破合同并使其可读写是没有意义的。

我在这一点上和Microsoft在一起。
假设我是一位新程序员,被告知要针对Baseclass派生进行编码。我写了一些假设不能写入Bar的东西(因为Baseclass明确声明它是一个get only属性)。现在,根据您的推导,我的代码可能会损坏。例如

public class BarProvider
{ BaseClass _source;
  Bar _currentBar;

  public void setSource(BaseClass b)
  {
    _source = b;
    _currentBar = b.Bar;
  }

  public Bar getBar()
  { return _currentBar;  }
}

由于不能按照BaseClass接口设置Bar,BarProvider认为缓存是一件安全的事-因为Bar不能修改。但是,如果在派生中可以设置set,则如果有人在外部修改_source对象的Bar属性,则此类可以提供陈旧的值。重点是“ 保持开放,避免做鬼sneak的事情并使人感到惊讶

更新Ilya Ryzhenkov问:“为什么接口不按照相同的规则运行?” 嗯..我想到这变得更加泥泞。
接口是一个合同,上面写着“期望实现具有名为Bar的读取属性”。个人而言,如果看到接口,则不太可能将其假定为只读。当我在接口上看到一个get-only属性时,我将其读取为“任何实现都会公开此属性Bar”……在它单击的基类上,因为“ Bar是只读属性”。当然,从技术上讲,您并没有违反合同。因此,您在某种意义上是正确的。.最后,我要说:“使误解变得尽可能困难”。


94
我还是不相信。即使没有显式的setter,也不能保证该属性将始终返回同一对象-仍然可以通过其他方法对其进行更改。
ripper234

34
那么接口是否应该一样呢?您可以在接口上具有readonly属性,并在实现类型上具有读/写功能。
伊利亚·里珍科夫

49
我不同意:基类仅声明该属性没有设置器;与只读属性不同。“只读”仅是为其分配的含义。C#完全没有内置任何相关保证。您可以具有每次都会更改的get-only属性,或者具有setter抛出的get / set属性InvalidOperationException("This instance is read-only")
罗曼·斯塔科夫

21
将getter和setter作为方法来看,除了添加新方法外,我不明白为什么它应该是“违约”。一个基类合同无关什么功能并不存在,只有什么存在。
Dave Cousineau 2012年

37
-1我不同意这个答案,并发现它是错误的。因为基类定义了任何类都必须遵守的行为(请参阅Liskov的替代原理),但没有(也不应)限制添加行为。基类只能定义行为必须是什么,并且不能(也不应)指定行为“必须不是”(即“在具体级别上不可写”)。
Marcel Valdez Orozco

39

我认为主要原因是语法太明确,以至于无法以其他任何方式工作。这段代码:

public override int MyProperty { get { ... } set { ... } }

明确指出getset都是覆盖。set基类中没有任何内容,因此编译器会抱怨。就像您无法覆盖基类中未定义的方法一样,您也无法覆盖setter。

您可能会说编译器应该猜测您的意图,并且仅将重写应用于可以重写的方法(在这种情况下,即吸气剂),但这违背了C#设计原则之一-编译器不得猜测您的意图,因为在您不知情的情况下可能会猜错。

我认为以下语法可能会做得很好,但是正如Eric Lippert一直说的那样,即使要实现这样的次要功能,仍然要付出很大的努力...

public int MyProperty
{
    override get { ... }
    set { ... }
}

或者,对于自动实现的属性,

public int MyProperty { override get; set; }

19

我今天偶然发现了一个同样的问题,我认为有一个很正当的理由想要这个。

首先,我想争论一下,拥有仅获取属性并不一定会转换为只读。我将其解释为“可以从此接口/抽象获取此值”,这并不意味着该接口/抽象类的某些实现不需要用户/程序显式设置此值。抽象类用于实现部分所需功能的目的。我绝对没有理由说,继承的类不能在不违反任何合同的情况下添加setter。

以下是我今天需要的简化示例。我最终不得不在我的界面中添加一个setter来解决这个问题。添加设置器而不添加例如SetProp方法的原因是,接口的一个特定实现使用DataContract / DataMember进行Prop的序列化,如果我仅出于此目的添加另一个属性,则将不必要地变得复杂序列化。

interface ITest
{
    // Other stuff
    string Prop { get; }
}

// Implements other stuff
abstract class ATest : ITest
{
    abstract public string Prop { get; }
}

// This implementation of ITest needs the user to set the value of Prop
class BTest : ATest
{
    string foo = "BTest";
    public override string Prop
    {
        get { return foo; }
        set { foo = value; } // Not allowed. 'BTest.Prop.set': cannot override because 'ATest.Prop' does not have an overridable set accessor
    }
}

// This implementation of ITest generates the value for Prop itself
class CTest : ATest
{
    string foo = "CTest";
    public override string Prop
    {
        get { return foo; }
        // set; // Not needed
    }
}

我知道这只是一篇“我的2美分”的帖子,但是我对原始的发帖人感同身受,并试图合理地认为这对我来说是一件好事,特别是考虑到直接从继承人继承时没有相同的限制接口。

同样,关于使用new而不是override的提述在这里也不适用,它根本行不通,即使这样做也不会给您想要的结果,即接口所描述的虚拟getter。


2
或者,就我而言,{get; 私人套装;}。我不会违反任何合同,因为该合同仍然是私人合同,只涉及派生类。
Machtyn 2015年

16

这是可能的

文艺青年最爱的 - 你可以重写一个只能获得法与制定者,如果你想。基本上就是:

  1. 创建一个new具有相同名称的a get和a 的属性set

  2. 如果您不执行其他任何操作,则在get通过其基类型调用派生类时,仍将调用旧方法。要解决此问题,请添加一个abstract用于overrideget方法的中间层,以强制其返回新get方法的结果。

这使我们能够使用get/ 覆盖属性,set即使它们在基本定义中缺少属性也是如此。

作为奖励,您还可以根据需要更改退货类型。

  • 如果基本定义是get-only,则可以使用派生更多的返回类型。

  • 如果基本定义是set-only,则可以使用派生较少的返回类型。

  • 如果基本定义已经是get/ set,则:

    • 您可以使用更衍生的返回类型,如果你把它set-only;

    • 您可以使用衍生少返回类型,如果你把它get-only。

在所有情况下,都可以根据需要保留相同的返回类型。为了简单起见,以下示例使用相同的返回类型。

情况:既有get属性

您有一些无法修改的类结构。也许它只是一个类,或者它是一个预先存在的继承树。无论如何,您都想向set属性添加方法,但不能这样做。

public abstract class A                     // Pre-existing class; can't modify
{
    public abstract int X { get; }          // You want a setter, but can't add it.
}
public class B : A                          // Pre-existing class; can't modify
{
    public override int X { get { return 0; } }
}

问题:无法overrideget-only与get/set

您想override使用get/ set属性,但无法编译。

public class C : B
{
    private int _x;
    public override int X
    {
        get { return _x; }
        set { _x = value; }   //  Won't compile
    }
}

解决方案:使用abstract中间层

虽然您不能直接override使用get/ set属性,但可以

  1. 创建一个具有相同名称的new get/ set属性。

  2. overrideget方法与新get方法的访问者一起确保一致性。

因此,首先编写abstract中间层:

public abstract class C : B
{
    //  Seal off the old getter.  From now on, its only job
    //  is to alias the new getter in the base classes.
    public sealed override int X { get { return this.XGetter; }  }
    protected abstract int XGetter { get; }
}

然后,编写不会更早编译的类。这次将编译,因为您实际上不是override在使用get-only属性;相反,您将使用new关键字替换它。

public class D : C
{
    private int _x;
    public new virtual int X { get { return this._x; } set { this._x = value; } }

    //  Ensure base classes (A,B,C) use the new get method.
    protected sealed override int XGetter { get { return this.X; } }
}

结果:一切正常!

显然,这按预期工作D

var test = new D();
Print(test.X);      // Prints "0", the default value of an int.

test.X = 7;
Print(test.X);      // Prints "7", as intended.

一切仍然有效-AS-目标观察时,D它的基类之一,例如AB。但是,它起作用的原因可能不太明显。

var test = new D() as B;
//test.X = 7;       // This won't compile, because test looks like a B,
                    // and B still doesn't provide a visible setter.

但是,的基类定义get最终仍会被派生类的定义所覆盖get,因此它仍然是完全一致的。

var test = new D();
Print(test.X);      // Prints "0", the default value of an int.

var baseTest = test as A;
Print(test.X);      // Prints "7", as intended.

讨论区

此方法允许您将set方法添加到get-only属性。您还可以使用它来执行以下操作:

  1. 将任何属性更改为get-only,set-only或get-and- set属性,而不管它在基类中是什么。

  2. 更改派生类中方法的返回类型。

主要缺点是要做更多的编码,并且abstract class在继承树中增加了额外的代码。对于带有参数的构造函数,这可能会有些烦人,因为必须在中间层中复制/粘贴这些参数。


提出了自己的问题:stackoverflow.com/questions/22210971
2014年

不错的方法(+1)。但是,我怀疑这是否可以与实体框架一起顺利使用。
Mike de Klerk

9

我同意不能覆盖派生类型中的getter是一种反模式。只读指定缺少实现,而不是纯功能的契约(由最高投票答案表示)。

我怀疑微软有这个局限性,可能是因为引起了同样的误解,或者可能是因为简化了语法。但是,现在可以将范围应用于单独获取或设置,也许我们可以希望重写也可以。

最高投票答案表明了一个误解,即只读属性应该比读/写属性更“纯”,这是荒谬的。只需看一下框架中许多常见的只读属性即可;该值不是常数/纯粹是函数性的;例如,DateTime.Now是只读的,但除纯函数值以外的任何值。尝试“缓存”只读属性的值(假设下次该属性将返回相同的值)是有风险的。

无论如何,我都使用以下策略之一来克服此限制;两者都不尽如人意,但会让您在这种语言缺陷之外li行:

   class BaseType
   {
      public virtual T LastRequest { get {...} }
   }

   class DerivedTypeStrategy1
   {
      /// get or set the value returned by the LastRequest property.
      public bool T LastRequestValue { get; set; }

      public override T LastRequest { get { return LastRequestValue; } }
   }

   class DerivedTypeStrategy2
   {
      /// set the value returned by the LastRequest property.
      public bool SetLastRequest( T value ) { this._x = value; }

      public override T LastRequest { get { return _x; } }

      private bool _x;
   }

DateTime.Now纯粹是功能性的,因为它没有副作用(可以想象,花时间执行的事实可能被称为副作用,但是由于执行时间(至少在有界和短时)不予考虑任何其他方法的副作用,我也不认为这是一种方法)。
2012年

1
嗨,超级猫 关于防止函数纯净的外部可观察到的副作用,您是正确的,但另一个约束是,纯函数结果值必须取决于参数。因此,作为功能的纯静态属性必须既不变又不变。复杂的编译器可以将没有参数的所有后续对纯函数的调用替换为第一次调用返回的结果。
T.Tobler

您是正确的,我的用词不精确,但是我认为某种东西是只读属性而不是方法的适当性取决于缺少副作用而不是纯度。
2013年

2

您也许可以通过创建新属性来解决该问题:

public new int Bar 
{            
    get { return 0; }
    set {}        
}

int IBase.Bar { 
  get { return Bar; }
}

4
但是您只能在实现接口时执行此操作,而不能从基类继承时执行此操作。您必须选择另一个名称。
凌晨

我假设示例类实现IBase(类似于公共接口IBase {int Bar {get;}}),否则在实现类时,不允许int IBase.Bar {...}。然后,您可以简单地同时创建带有get和set的常规属性Bar,但是,接口中的Bar属性不需要设置。
2015年

1

我可以理解您的所有观点,但实际上,在这种情况下,C#3.0的自动属性变得毫无用处。

你不能做这样的事情:

public class ConcreteClass : BaseClass
{
    public override int Bar
    {
        get;
        private set;
    }
}

IMO,C#不应限制这种情况。开发人员有责任相应地使用它。


我不明白你的意思。您是否同意C#应该允许添加设置器,或者您是否与其他大多数回答此问题的人一样?
ripper234

2
就像我说的,IMO,C#应该允许添加一个setter。开发人员有责任相应地使用它。
Thomas Danecker

1

问题在于,无论出于何种原因,Microsoft都决定应该有三种不同类型的属性:只读,只写和读写,在给定的上下文中只有给定的签名可以存在其中一种。属性只能由相同声明的属性覆盖。要执行您想要的操作,有必要创建两个具有相同名称和签名的属性-其中一个是只读的,而另一个是可读写的。

就个人而言,我希望可以取消“属性”的整个概念,除了可以将属性式语法用作调用“ get”和“ set”方法的语法糖外。这不仅可以方便使用“添加集”选项,还可以允许“获取”返回与“集”不同的类型。尽管这种能力不会经常使用,但是有时使“ get”方法返回包装对象,而“ set”可以接受包装数据或实际数据有时会很有用。


0

为了解决此问题,请使用以下解决方法:

var UpdatedGiftItem = // object value to update;

foreach (var proInfo in UpdatedGiftItem.GetType().GetProperties())
{
    var updatedValue = proInfo.GetValue(UpdatedGiftItem, null);
    var targetpropInfo = this.GiftItem.GetType().GetProperty(proInfo.Name);
    targetpropInfo.SetValue(this.GiftItem, updatedValue,null);
}

这样,我们可以在只读属性上设置对象值。可能无法在所有情况下都起作用!


1
您确定可以通过不存在的反射来调用setter(就像在描述的getter-only属性中一样)吗?
或Mapper 2013年

0

您应该更改问题标题,以详细说明问题仅是有关覆盖抽象属性的问题,或者是有关问题一般是覆盖类的get-only属性的问题。


如果是前者(覆盖抽象属性)

该代码是无用的。仅基类不能告诉您被迫重写Get-Only属性(也许是接口)。基类提供了通用功能,这些功能可能需要实现类的特定输入。因此,通用功能可能会调用抽象属性或方法。在给定的情况下,常见的功能性方法应要求您重写一个抽象方法,例如:

public int GetBar(){}

但是,如果您对此没有控制权,并且基类的功能从其自己的公共属性(怪异)中读取,则只需执行以下操作:

public abstract class BaseClass
{
    public abstract int Bar { get; }
}

public class ConcreteClass : BaseClass
{
    private int _bar;
    public override int Bar
    {
        get { return _bar; }
    }
    public void SetBar(int value)
    {
        _bar = value;
    }
}

我想指出(怪异的)评论:我要说的一种最佳实践是,一个类不使用其自己的公共属性,而在它们存在时使用其私有/受保护的字段。所以这是一个更好的模式:

public abstract class BaseClass {
    protected int _bar;
    public int Bar { get { return _bar; } }
    protected void DoBaseStuff()
    {
        SetBar();
        //Do something with _bar;
    }
    protected abstract void SetBar();
}

public class ConcreteClass : BaseClass {
    protected override void SetBar() { _bar = 5; }
}

如果是后者(覆盖类的get-only属性)

每个非抽象属性都有一个setter。否则,它是无用的,您不应该在意它。Microsoft不必允许您做您想做的事。原因是:安装员以某种形式存在,并且您可以轻松地实现想要的Veerryy

基类,或者你可以读取与属性的任何类{get;},有一些类型的暴露二传手该属性的。元数据将如下所示:

public abstract class BaseClass
{
    public int Bar { get; }
}

但是实现将具有复杂性范围的两个方面:

最少复杂度:

public abstract class BaseClass
{
    private int _bar;
    public int Bar { 
        get{
            return _bar;
        }}
    public void SetBar(int value) { _bar = value; }
}

最复杂:

public abstract class BaseClass
{
    private int _foo;
    private int _baz;
    private int _wtf;
    private int _kthx;
    private int _lawl;

    public int Bar
    {
        get { return _foo * _baz + _kthx; }
    }
    public bool TryDoSomethingBaz(MyEnum whatever, int input)
    {
        switch (whatever)
        {
            case MyEnum.lol:
                _baz = _lawl + input;
                return true;
            case MyEnum.wtf:
                _baz = _wtf * input;
                break;
        }
        return false;
    }
    public void TryBlowThingsUp(DateTime when)
    {
        //Some Crazy Madeup Code
        _kthx = DaysSinceEaster(when);
    }
    public int DaysSinceEaster(DateTime when)
    {
        return 2; //<-- calculations
    }
}
public enum MyEnum
{
    lol,
    wtf,
}

我的意思是,无论哪种方式,您都会看到塞特犬。在您的情况下,您可能想要覆盖,int Bar因为您不希望基类处理它,无权查看它的处理方式,或者被责成违背您的意愿快速地编写一些代码。

无论是前者还是后者(结论)

长篇短篇:Microsoft无需更改任何内容。您可以选择如何设置实现类,以及在没有构造函数的情况下使用全部或全部不使用基类。


0

解决方案仅适用于一小部分用例,但是:在C#6.0中,将自动为覆盖的仅吸气剂属性添加“只读”设置器。

public abstract class BaseClass
{
    public abstract int Bar { get; }
}

public class ConcreteClass : BaseClass
{
    public override int Bar { get; }

    public ConcreteClass(int bar)
    {
        Bar = bar;
    }
}

-1

因为那样会破坏封装和实现隐藏的概念。请考虑以下情况:创建类并交付它,然后类的使用者使自己能够设置最初仅为其提供吸气剂的属性。它会有效地破坏您可以在实现中依赖的类的所有不变量。


1
-1:拥有二传手不会自动使后代打破任何不变式。设置者仍然只能更改后代已经可以更改的内容。
Roman Starkov 2011年

@RomanStarkov是的。但是这个帖子的问题是;为什么不能将setter添加到不与您签约的抽象中。您的评论在相反的问题中是适当的;如果后代无论如何都可以完全控制其私有字段,为什么Microsoft允许您抽象创建ReadOnly属性?
Suamere

+1:这个问题是关于为什么Microsoft不允许您违约。尽管您不赞成投票的原因更多是关于Microsoft为什么允许合同仅包含只读属性的原因。因此,此答案在上下文中是正确的。
Suamere

@Suamere合同未声明不能更改该属性。它仅说明存在一个可以读取的属性。添加二传手不会破坏该合同。您可以解释为创建只读属性的意图,但是您不能在C#6中保证无法更改它,因此您所考虑的合同实际上并不存在。考虑一下接口:它可以在gettable(不是get-only!)属性上提供合同。可以通过get + set属性很好地实现此接口。
罗曼·斯塔科夫

您是从具体作者的角度来解决这个问题的。他可以随意更改它。我是从基类作者的角度来处理这个问题的->将其作为实现类的最终使用者。基类的作者不希望将来的具体类的任何使用者都可以更改该属性,而具体类的作者没有公开处理个案的特殊方法。因为在基类中,该属性被视为不可变的,并且只能通过将其公开来进行通信。
Suamere

-1

这并非不可能。您只需要在媒体资源中使用“ new”关键字即可。例如,

namespace {
    public class Base {
        private int _baseProperty = 0;

        public virtual int BaseProperty {
            get {
                return _baseProperty;
            }
        }

    }

    public class Test : Base {
        private int _testBaseProperty = 5;

        public new int BaseProperty {
            get {
                return _testBaseProperty;
            }
            set {
                _testBaseProperty = value;
            }
        }
    }
}

看来这种方法满足了讨论的双方。使用“ new”会破坏基类实现和子类实现之间的契约。当一个类可以具有多个合同(通过接口或基类)时,这是必需的。

希望这可以帮助


29
这个答案是错误的,因为标记的属性new不再覆盖虚拟基址。特别是,如果基本属性是abstract,如原始文章中所述,则不可能new在非抽象子类中使用关键字,因为您必须覆盖所有抽象成员。
Timwi

这是非常危险的,因为尽管对象相同,但以下内容仍会返回不同的结果:Test t = new Test(); Base b = t; Console.WriteLine(t.BaseProperty)给您5,Console.WriteLine(b.BaseProperty)给您0,并且当您的后继者必须调试它时,您最好走得很远。
Mark Sowul 2014年

我同意马克,这太讨厌了。如果两个BaseProperty实现都由同一个变量支持,则可以通过恕我直言。IE:使_baseProperty受保护并废除_testBaseProperty。另外,由于您实际上并未覆盖AFAIK,因此Base中的实现不必是虚拟的。
Steazy 2014年

问题的大多数答案都可以得到有效的意见和投入。但是除了前面的评论之外,我对这个答案的主要批评是,我认为实际的问题可能实际上是关于消费者无法控制的代码库中的抽象属性。所以我的批评是这个答案可能不适合这个问题。
Suamere

-1

基类中的只读属性指示该属性表示始终可以从类内部确定的值(例如,与对象的(db-)上下文匹配的枚举值)。因此,确定值的责任在于类中。

添加设置器将在此处引起一个尴尬的问题:如果将值设置为除已存在的单个可能值以外的任何值,都将发生验证错误。

但是,规则通常会有例外。例如,很可能在一个派生类中,上下文将可能的枚举值缩小到十分之三(十分之三),但是此对象的用户仍然需要确定哪个是正确的。派生类需要将确定值的责任委托给此对象的用户。 重要的是要认识到该对象的用户应充分了解此异常,并承担设置正确值的责任。

在这种情况下,我的解决方案是将属性保留为只读,并向派生类添加新的读写属性以支持异常。覆盖原始属性将仅返回新属性的值。新属性可以具有适当的名称,以正确指示此异常的上下文。

这也支持了有效的说法:Gishu提出的“使误解越发严重”。


1
ReadableMatrix具有子类型ImmutableMatrix和的类(具有两个参数的只读索引属性)不会暗示任何笨拙MutableMatrix。只需读取一个矩阵,并且不在乎将来是否会更改的代码,都可以接受类型的参数,ReadableMatrix并且对可变或不可变的子类型非常满意。
2012年

附加的setter可以修改类中的私有变量。然后,基类的所谓“只读”属性仍将确定“从类内部”的值(通过读取新的私有变量)。我看不到那里的问题。还要看看例如,List<T>.Count它做什么:不能被分配给它,但这并不意味着它是“只读的”,因为它不能被该类的用户修改。可以通过添加和删除列表项来很好地对其进行修改,尽管可以间接进行修改。
OR Mapper 2013年

-2

因为在IL级别,读/写属性转换为两个方法(getter和setter)。

覆盖时,您必须继续支持基础接口。如果您可以添加一个setter,那么您将有效地添加一个新方法,就类的接口而言,该方法对于外界仍然是不可见的。

的确,添加新方法本身并不会破坏兼容性,但是由于它将保持隐藏状态,因此决定禁止这样做是完全合理的。


2
我对这里的“外部世界”不太在意。我想向类添加功能,该功能仅对知道特定类而不是基础的代码始终可见。
ripper234

@ ripper234请参阅Matt Bolt的答案:如果要使新属性仅对派生类的用户可见,则应使用new而不是override
Dan Berindei 2010年

1
它不会保持隐藏。您就像在说不能将新方法添加到子类中,因为新方法将“对外界隐藏”。当然,从基类的角度来看,它仍然是隐藏的,但是可以从子类的客户端访问它。(即影响吸气剂的返回值)
羊皮的

y,那根本不是我要说的。我的意思是,正如您所指出的那样,“从基类的角度来看”它仍然是隐藏的。这就是为什么我附加了“就您的类的界面而言”。如果要对基类进行子类化,则几乎可以肯定,“外部世界”将引用具有基类类型的对象实例。如果他们直接使用您的具体类,则您将不需要与基类兼容,并且可以通过各种方式使用new您的添加类。
Ishmaeel 2011年

-2

因为具有只读属性(没有设置器)的类可能有充分的理由。例如,可能没有任何基础数据存储。允许您创建二传手会破坏班级制定的合同。糟糕的OOP。


投票。这非常简洁。微软为什么要允许基类的消费者违反合同?我同意我的答案太长而混乱的简短版本。大声笑。如果您是基类的使用者,则不希望违反合同,但是可以通过几种不同的方式来实现它。
Suamere
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.