Making members in subclasses readonly

Let's say I have the class A with member int number which has a getter and a setter.

Then I make a subclass of A and call it B. Now in the class B I wish to keep the member number, but in this class I want to impose the restriction that number is read-only. How can I do this?

Upvotes: 1

Views: 214

Answers (2)

John Alexiou
John Alexiou

Reputation: 29244

I agree with Sebastian's answer. Another option to consider is to use a common interface instead of direct inheritance

public interface IHasNumber 
{
    int Number { get; }
}

public class A : IHasNumber 
{ 
    public int Number { get; set; } 
}
public class B : IHasNumber 
{ 
    public int Number { get; } 
}

If you want to share the values then you must encapsulate A in B.

public class B : IHasNumber 
{ 
    public B(A data) { this.Data = data; }
    private A Data { get; private set; }
    public int Number { get { Data.Number; } } 
 }

To be used as

{
    var A = new A();
    A.Number = 100;   // ok
    var B = new B(A);
    B.Number = 200;   // error
    Console.WriteLine(B.Number);  // prints 100
}

Upvotes: 3

Sebastian Negraszus
Sebastian Negraszus

Reputation: 12215

The need for that is usually a hint that your design is not optimal (as it violates the Liskov substitution principle). Therefore, C# does not really support it. However, here are two ways to kind of implement it:

(1) Hide the property in the descendent and provide a new property that replaces the getter of the base class. But this does not really protect the property, since you can just cast to the base class:

class A
{
  public int Number { get; set; }
}

class B : A
{
  public new int Number
  {
    get { return base.Number; }
  }
}

B b = new B();
// b.Number = 42; // This does not work.
A a = b;
a.Number = 42;
Console.WriteLine(b.Number); // == 42. Oops.

(2) Override the setter with an exception throw. But a wrong usage now causes a runtime error instead of a compiler error which is not nice. Consider adding a bool CanSetNumber property to the base (.NET does something similar with Stream.CanSeek and Seek).

class A
{
  public virtual int Number { get; set; }
}

class B : A
{
  public override int Number
  {
    get { return base.Number; }
    set { throw new InvalidOperationException("B.Number is readonly!"); }
  }
}

B b = new B();
b.Number = 42; // BAM!

Upvotes: 8

Related Questions