C# 使派生类中的属性为只读
我正在重写我的派生类中的一个属性,我想使它成为只读的。C#编译器不允许我更改访问修饰符,因此它必须保持公共C# 使派生类中的属性为只读,c#,properties,overriding,access-modifiers,C#,Properties,Overriding,Access Modifiers,我正在重写我的派生类中的一个属性,我想使它成为只读的。C#编译器不允许我更改访问修饰符,因此它必须保持公共 最好的方法是什么?我是否应该在set{}中抛出invalidoOperationException?让setter在派生类中抛出invalidoOperationException违反了规则。本质上使setter的使用与基类的类型相关,这基本上消除了多态性的值 派生类必须遵守其基类的约定。如果setter在所有情况下都不合适,那么它就不属于基类 解决这个问题的一种方法是稍微分解层次结构 c
最好的方法是什么?我是否应该在
set{}
中抛出invalidoOperationException
?让setter在派生类中抛出invalidoOperationException
违反了规则。本质上使setter的使用与基类的类型相关,这基本上消除了多态性的值
派生类必须遵守其基类的约定。如果setter在所有情况下都不合适,那么它就不属于基类
解决这个问题的一种方法是稍微分解层次结构
class C1 {
public virtual int ReadOnlyProperty { get; }
}
class C2 {
public sealed override int ReadOnlyProperty {
get { return Property; }
}
public int Property {
get { ... }
set { ... }
}
}
在此场景中,您遇到问题的类型可以继承
C1
,其余类型可以切换为从C2
派生。您可以隐藏原始实现并返回基本实现:
class Foo
{
private string _someString;
public virtual string SomeString
{
get { return _someString; }
set { _someString = value; }
}
}
class Bar : Foo
{
public new string SomeString
{
get { return base.SomeString; }
private set { base.SomeString = value; }
}
}
namespace ConsoleApplication3
{
class Program
{
static void Main( string[] args )
{
Foo f = new Foo();
f.SomeString = "whatever"; // works
Bar b = new Bar();
b.SomeString = "Whatever"; // error
}
}
}
然而,。正如Jared提到的,这是一种奇怪的情况。为什么不首先在基类中将setter设置为private或protected?不允许在C#中隐藏基类的公共成员,因为有人可以获取派生类的实例,将其填充到基类的引用中,并以这种方式访问属性
如果您想使一个类提供另一个类的大部分(但不是全部)接口,那么必须使用聚合。不要从“基类”继承,只需在“派生”中逐个值包含一个,并为希望公开的“基类”功能部分提供自己的成员函数。然后,这些函数可以将调用转发到相应的“基类”函数。只需使用new关键字定义属性,并且不在派生类中提供Setter方法。这也将隐藏基类属性,但是正如mjfgates提到的那样,仍然可以通过将基类属性分配给基类实例来访问基类属性。这就是多态性。在某些情况下,您描述的模式是合理的。例如,拥有一个抽象类
MaybeMutableFoo
,从中派生子类型MutableFoo
和ImmutableFoo
,可能会有所帮助。这三个类都包括一个IsMutable
属性和方法AsMutable()
,AsNewMutable()
,以及AsImmutable()
在这种情况下,MaybeMutableFoo
公开读写属性是完全合适的,前提是它的契约明确规定除非IsMutable
返回true,否则setter可能无法工作。具有类型为的字段的对象可能是可变foo
,而该字段恰好包含ImmutableFoo
的实例,除非或直到它必须写入该实例,否则该对象可能会非常满意该实例,因此它将使用通过AsMutable()
返回的对象替换该字段,然后将其用作可变foo(它会知道它是可变的,因为它刚刚替换了它)。拥有MaybeMutableFoo
include一个setter可以避免在引用可变实例后在字段上进行任何未来的类型转换
允许这种模式的最佳方式是避免实现虚拟或抽象属性,而是实现其getter和setter链接到虚拟或抽象方法的非虚拟属性
public class MaybeMutableFoo
{
public string Foo {get {return Foo_get();} set {Foo_set(value);}
protected abstract string Foo_get();
protected abstract void Foo_set(string value};
}
然后派生类ImmutableFoo
可以声明:
new public string Foo {get {return Foo_get();}
使其
Foo
属性为只读,而不干扰为抽象Foo\u get()和Foo\u set()编写重写的能力
方法。请注意,Foo
的只读替换不会更改属性get的行为;只读版本链接到与基类属性相同的基类方法。这样做将确保有一个用于更改属性getter的修补点,一个用于更改setter的修补点,以及即使属性本身被重新定义,这些补丁点也不会改变。我认为在这种情况下,更好的解决方案是新关键字
public class Aclass {
public int ReadOnly { get; set; }
}
public class Bclass : Aclass {
public new int ReadOnly { get; private set; }
}
我想我们需要更多的上下文。除了如果你在你的例子中使用“Foo f2=b;f.SomeString=“eeba geeba!”;编译器允许你使用。@mjfgates:我猜你的意思是Foo f=new Bar();f.SomeString=“blah”
?这就是我没有走这条路线的原因。我无法更改基类,因为我是从标准ASP.NET web控件派生的。不,我指的是我编写的。在这种情况下,您调用Foo.SomeString是因为SomeString在Bar中不是多态的,它隐藏了Foo实现。@Ed:我指的是mjfgates编写的内容(尽管间接地是关于你写的东西)。无论如何,我理解这是如何工作的,不希望两种实现根据您使用的类型而工作不同。抱歉,我错过了在手机上的响应。我100%同意这不是最佳的。但问题来自最初的请求。如果您做出了错误的设计选择,您可能会做出更糟糕的设计c我不会试图隐藏setter并避免破坏接口,因此如果基类有一个IsReadOnly
属性并抛出自己的异常,那么它就可以了?这就是NameObjectCollectionBase
NameValueCollection
中的HttpValueCollection
的方式ritance有效,被页面的请求使用。Param
。我理解该原则背后的原因,但在NameObjectCollectionBase
的情况下,它与您的陈述相矛盾:如果setter在所有情况下都不合适,那么它就不属于基类。
不幸的是,我是使用.NETC