在派生类中使属性只读

时间:2010-12-09 22:52:01

标签: c# properties override access-modifiers

我正在覆盖我的派生类中的一个属性,我想让它只读。 C#编译器不允许我更改访问修饰符,因此它必须保持公开。

最好的方法是什么?我应该在InvalidOperationException中抛出set { }吗?

6 个答案:

答案 0 :(得分:8)

让setter在派生类中抛出InvalidOperationException会违反Liskov Subsitution Principle。本质上是将setter contextual用于基类的类型,这基本上消除了多态的价值。

您的派生类必须尊重它的基类合同。如果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

派生

答案 1 :(得分:3)

您可以隐藏原始实现并返回基本实现:

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
        }
    }
}

然而,。正如贾里德所暗示的那样,这是一种奇怪的情况。为什么不首先让你的setter私有或在基类中受保护?

答案 2 :(得分:1)

我认为在这种情况下,更好的解决方案是新关键字

public class Aclass {        
    public int ReadOnly { get; set; }
}

public class Bclass : Aclass {        
    public new int ReadOnly { get; private set; }
}

答案 3 :(得分:0)

您不能在C#中隐藏基类的公共成员,因为有人可以获取派生类的实例,将其填充到对基类的引用中,并以这种方式访问​​属性。

如果你想创建一个提供另一个类的接口的大部分但不是全部的类,你将不得不使用聚合。不要继承“基类”,只需在值“派生”中包含一个,并为要公开的“基类”功能部分提供自己的成员函数。然后,这些函数可以将调用转发到适当的“基类”函数。

答案 4 :(得分:0)

只需使用new关键字定义属性,并在派生类中提供Setter方法。这也将隐藏基类属性,但是正如mjfgates所提到的,仍然可以通过将基类属性分配给基类实例来访问基类属性。多态性。

答案 5 :(得分:0)

在某些情况下,您描述的模式是合理的。例如,拥有一个抽象类MaybeMutableFoo可能会有所帮助,派生类型MutableFooImmutableFoo。这三个类都包含IsMutable属性,方法AsMutable()AsNewMutable()AsImmutable()

在这种情况下,MaybeMutableFoo公开读写属性是完全正确的,如果它的契约明确指定setter可能不起作用,除非IsMutable返回true。具有类型MaybeMutableFoo的字段恰好包含ImmutableFoo实例的对象可能对该实例非常满意,除非或直到它必须写入它,然后它将用一个实例替换该字段对象通过AsMutable()返回,然后将其用作可变foo(它会知道它是可变的,因为它刚刚替换它)。让MaybeMutableFoo包含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_get()Foo_set()方法的代码覆盖功能。请注意,Foo的只读替换不会更改属性get的行为;只读版本链与基类属性相同的基类方法。以这种方式做事将确保有一个补丁点用于更改属性getter,另一个用于更改setter,即使属性本身被重新定义,这些补丁点也不会改变。