Make property readonly in derived class

只谈情不闲聊 提交于 2021-02-08 13:18:12

问题


I'm overriding a property in my derived class that I would like to make it readonly. The C# compiler won't let me change the access modifiers, so it must stay public.

What's the best way to do this? Should I just throw an InvalidOperationException in set { }?


回答1:


Having the setter throw an InvalidOperationException in a derived class violates the Liskov Subsitution Principle. Essentially makes the usage of the setter contextual to the type of the base class which essentially eliminates the value of polymorphism.

Your derived class must respect the contract of it's base class. If the setter is not appropriate in all circumstances then it doesn't belong on the base class.

One way to work around this is to break the hierarchy up a little bit.

class C1 { 
  public virtual int ReadOnlyProperty { get; } 
}
class C2 { 
  public sealed override int ReadOnlyProperty { 
    get { return Property; }
  }
  public int Property {
    get { ... }
    set { ... }
  }
}

Your type you're having problems with could inherit C1 in this scenario and the rest could switch to derive from C2




回答2:


You can hide the original implementation and return the base implementation:

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

However,. as Jared has alluded to, this is kind of a weird situation. Why don't you make your setter private or protected in the base class to begin with?




回答3:


I think i this situation the better solution is new keyword

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

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



回答4:


You're not allowed to hide your base class' public members in C#, because somebody could take an instance of your derived class, stuff it into a reference to the base class, and access the property that way.

If you want to make a class that provided most, but not all, of the interface of another class, you'll have to use aggregation. Don't inherit from the "base class," just include one in the "derived" one by value, and provide your own member functions for the portions of the "base class" functionality you wish to expose. Those functions can then just forward the calls on to the appropriate "base class" functions.




回答5:


Just define the property with new keyword and don provide the Setter method in the derived class. This will hide the base class property as well, however as mjfgates mentioned one can still access the base class property by assigning it to a base class instance. Thats polymorphism.




回答6:


There are some cases where the pattern you describe is justifiable. For example, it may be helpful to have an abstract class MaybeMutableFoo, from which are derived subtypes MutableFoo and ImmutableFoo. All three classes include an IsMutable property, and methods AsMutable(), AsNewMutable(), and AsImmutable().

In that situation, it would be entirely proper for the MaybeMutableFoo to expose a read-write property, if its contract explicitly specifies that the setter may not work unless IsMutable returns true. An object which has a field of type MaybeMutableFoo that happens to hold an instance of ImmutableFoo could be perfectly happy with that instance unless or until it had to write to it, whereupon it would replace the field with an object returned via AsMutable() and then use it as a mutable foo (it would know it was mutable, since it had just replaced it). Having MaybeMutableFoo include a setter would avoid the need to do any future typecasts on the field once it was made to refer to a mutable instance.

The best way to allow for such a pattern is to avoid implementing virtual or abstract properties, but instead implement non-virtual properties whose getters and setters chain to virtual or abstract methods. If one has a base class

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

then a derived class ImmutableFoo may declare:

    new public string Foo {get {return Foo_get();}

to make its Foo property be read-only without interfering with the ability to code overrides for the abstract Foo_get() and Foo_set() methods. Note that the read-only replacement of Foo doesn't change the behavior of the property get; the read-only version chains to same the base-class method as the base-class property did. Doing things this way will ensure that there's one patch point for changing the property getter, and one for changing the setter, and those patch points won't change even if the property itself gets redefined.



来源:https://stackoverflow.com/questions/4403925/make-property-readonly-in-derived-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!