为什么不允许使用以下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”没有可重写的set访问器
发布于 2008-09-17 12:17:54
因为Baseclass的编写者已经显式声明Bar必须是只读属性。对于派生来说,打破这个契约并使其成为可读写是没有意义的。
在这个问题上,我和微软站在一起。
假设我是一个新的程序员,他被告知要针对Baseclass派生进行编码。我写了一些东西,假设Bar不能被写入(因为基类显式地声明它是一个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接口设置栏,因此BarProvider假定缓存是安全的-因为栏不能被修改。但是,如果在派生中可以设置,那么如果有人在外部修改了_source对象的Bar属性,这个类可能会提供陈旧的值。重点是“保持开放,避免偷偷摸摸的事情和让人惊讶”。
更新:Ilya Ryzhenkov问道:“为什么界面不遵循同样的规则?”嗯..。随着我的思考,这一点变得更加混乱。
接口是一种约定,它说“期望一个实现具有一个名为Bar的read属性。”我个人认为,如果我看到一个接口,我就不太可能假设它是只读的。当我在接口上看到get-only属性时,我会将其读作“任何实现都会公开此属性栏”……在基类上,它单击为“Bar is a read-only property”。当然,从技术上讲,你并没有违反合同..你做的更多。所以从某种意义上说你是对的..最后,我会说:“尽量避免误解的发生”。
发布于 2010-04-03 20:06:28
我认为主要原因很简单,因为语法太明确了,不能以其他方式工作。这段代码:
public override int MyProperty { get { ... } set { ... } }
非常明确,get
和set
都是重写。基类中没有set
,所以编译器会报错。就像你不能覆盖基类中没有定义的方法一样,你也不能覆盖setter。
您可能会说编译器应该猜测您的意图,并仅将覆盖应用于可以覆盖的方法(即本例中的getter ),但这违反了C#设计原则之一-编译器不能猜测您的意图,因为它可能在您不知道的情况下猜测错误。
我认为下面的语法可能会做得很好,但正如Eric Lippert一直说的那样,实现这样一个次要的功能仍然需要大量的努力……
public int MyProperty
{
override get { ... } // not valid C#
set { ... }
}
或者,对于自动实现的属性,
public int MyProperty { override get; set; } // not valid C#
发布于 2014-03-06 06:07:39
这是可能的。
tl;dr–如果需要,您可以使用setter重写get-only方法。它基本上就是:
new
属性,该属性具有使用相同名称的get
和set
。对新get
.的别名执行
override
操作之前的get
这使我们能够使用get
/set
覆盖属性,即使它们的基本定义中缺少设置器。
情况:预先存在的get
-only属性。
你有一些不能修改的类结构。也许它只是一个类,或者它是一个预先存在的继承树。不管是哪种情况,您都想将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; } }
}
问题:无法使用get
/set
对get
-only执行override
操作。
您希望使用get
/set
属性执行override
,但它不能编译。
public class C : B
{
private int _x;
public override int X
{
get { return _x; }
set { _x = value; } // Won't compile
}
}
解决方案:使用abstract
中间层。
虽然不能直接使用get
/set
属性进行override
,但可以
new
get
/set
属性。使用新的
override
方法的访问器对旧的get
方法执行override
操作,以确保consistency.因此,首先要编写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; }
}
然后,编写不能在前面编译的类。这次将编译它,因为您实际上并没有对get
-only属性执行override
操作;相反,您使用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; } }
}
结果:一切正常!
var d = new D();
var a = d as A;
var b = d as B;
var c = d as C;
Print(a.X); // Prints "0", the default value of an int.
Print(b.X); // Prints "0", the default value of an int.
Print(c.X); // Prints "0", the default value of an int.
Print(d.X); // Prints "0", the default value of an int.
// a.X = 7; // Won't compile: A.X doesn't have a setter.
// b.X = 7; // Won't compile: B.X doesn't have a setter.
// c.X = 7; // Won't compile: C.X doesn't have a setter.
d.X = 7; // Compiles, because D.X does have a setter.
Print(a.X); // Prints "7", because 7 was set through D.X.
Print(b.X); // Prints "7", because 7 was set through D.X.
Print(c.X); // Prints "7", because 7 was set through D.X.
Print(d.X); // Prints "7", because 7 was set through D.X.
讨论。
此方法允许您向get
-only属性添加set
方法。你也可以用它来做一些事情,比如:
get
-only、set
-only或get
--set
属性,而不管它在基类中是什么。主要的缺点是有更多的代码要做,并且在继承树中有额外的abstract class
。对于接受参数的构造函数来说,这可能有点麻烦,因为这些参数必须复制/粘贴到中间层中。
额外的好处:你可以改变属性的返回类型。
作为额外的好处,您还可以根据需要更改返回类型。
get
-only,则可以使用派生程度更高的返回类型。set
-only,则可以使用派生较少的返回类型。get
/set
,则:- you can use a more-derived return type _**if**_ you make it `set`-only;
- you can use a less-derived return type _**if**_ you make it `get`-only.
在所有情况下,如果您愿意,都可以保持相同的返回类型。
https://stackoverflow.com/questions/82437
复制相似问题