开发者

Make property readonly in derived class

开发者 https://www.devze.com 2023-01-30 08:18 出处:网络
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.

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


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


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?


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


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.


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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消