Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make a read only property writable in the derived class

Tags:

c#

What I want to achieve is the following : I have a property declared in the BaseClass. If this property is accessed via the base class' pointer, only the getter should be available but if the derived class pointer is used I want to be able to get and set the property. So the intellisense should not even show a setter for the base pointer.

public class BaseClass
{
     public virtual int MyProperty
     {
         get { return 1; }
         set {;}//This would show the setter in Intellisense
     }
}   

public class DerivedClass : BaseClass
{
     int intValue;

     public override int MyProperty
     {
         set { intValue = value;}
     }
}   

A realistic example:
Consider a situation where you have a Parent and Child class derived from the Person class. Imagine a property -RestrictionLevel, where both can read it but only the parent can set the value. Is there a better way to design this situation?

like image 846
alwayslearning Avatar asked Feb 11 '10 10:02

alwayslearning


1 Answers

The only way I could think of is to shadow the property with a new one:

public class DerivedClass : BaseClass
{
    int intValue;

    public new int MyProperty
    {
        get { return intValue; }
        set { intValue = value; }
    }
}  

Notice how the property is declared new instead of override. This means, of course, that MyProperty of the type DerivedClass has nothing to do with MyProperty of the type BaseClass, it's a brand new property that just happens to have the same name (thus hiding the one from the base class).

The result is this:

DerivedClass d = new DerivedClass();
d.MyProperty = 42;

BaseClass b = new DerivedClass();
b.MyProperty = 42;    /* compilation error: Property or indexer 
                                            'TheNamespace.BaseClass.MyProperty' 
                                            cannot be assigned to -- it is 
                                            read only */

Also, as @silky states in the comment:

(though I suggest you make it, and the parent, refer to the same variable to avoid a very confusing situation) but I really don't think this would ever be appropriate.

...you may want to have the new property access the one from the base class (through base.MyProperty, completed with a protected setter). Consider the following for instance:

DerivedClass d = new DerivedClass();
d.MyProperty = 42;

BaseClass b = d;
Console.WriteLine(b.MyProperty);  // prints 1

That said, I always feel a little dirty when using new (which, when I think about it, I am not sure that I have actually done in production code).

Update
Given the example scenario that you give (that I interpret in a way that a Parent is to be able to set the RestrictionLevel of a Child), it could be solved like this:

public enum RestrictionLevel
{
    Low,
    Medium,
    Grounded
}

public class Person
{
    public RestrictionLevel RestrictionLevel { get; private set; }
    protected static void SetRestrictionLevelInternal(Person person, RestrictionLevel restrictionLevel)
    {
        person.RestrictionLevel = restrictionLevel;
    }
}

public class Child : Person { }

public class Parent : Person
{
    public void SetRestrictionLevel(Child child, RestrictionLevel restrictionLevel)
    {
        SetRestrictionLevelInternal(child, restrictionLevel);
    }
}

This means that the following code is valid:

Child c = new Child();
Parent p = new Parent();
p.SetRestrictionLevel(c, RestrictionLevel.Grounded);

...but this one is not:

Child c = new Child();
c.SetRestrictionLevel(c, RestrictionLevel.Low);

The method SetRestrictionLevelInternal can be called from within any descendant type (including Child), but cannot be invoked from outside the type itself. So, you cannot invoke SetRestrictionLevelInternal on a Parent instance. In the above example, we choose to expose a public method, which in turn invokes the protected method.

like image 152
Fredrik Mörk Avatar answered Nov 14 '22 23:11

Fredrik Mörk