开发者

How to restrict overrided property to be read only

开发者 https://www.devze.com 2023-03-05 06:38 出处:网络
I am having following code. class A { public virtual int BoardSize { get; set; } } class B : A { p开发者_运维技巧ublic override int BoardSize

I am having following code.

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

    class B : A
    {
        p开发者_运维技巧ublic override int BoardSize
        {
            get{return 100;}
        }
    }

    Class Client
    {
        B b = new B();
        b.BoardSize = 55;
    }

In base class the property is read/write. but in derived class it is readonly and should always return 100. Although when I ran the code I found that it always returns 100 as expected.

But, I don't want client to set BoardSize in B class. So it should not allow client to write b.BoardSize = 55 at all.

How is it possible?


Short answer: Well... you can't!
Long answer:
You can hide the implementation of BoardSize from the base class using new:

class B : A
{
    public new int BoardSize
    {
        get{return 100;}
    }
}

This will make the following code invalid:

B b = new B();
b.BoardSize = 55;

But this will only make matters worse!
The following code IS valid:

A a = new B();
a.BoardSize = 55;
Console.WriteLine(a.BoardSize);
Console.WriteLine(((B)a).BoardSize);

and it prints

55
100

Conclusion:
You could use new to achieve your goal, but this will introduce serious problems in your code.
If you can't change A and B needs to derive from A then use this code:

class B : A
{
    public override int BoardSize
    {
        get{return 100;}
        set{throw new NotSupportedException();}
    }
}

This is consistent to the .NET framework. For example, ReadOnlyCollection throws this exception when you call Add (after casting it to ICollection<T>).


You have two options.

1) Throw an exception in the setter:

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

class B : A
{
  public override int BoardSize
  {
    get { return 100; }
    set {
      throw new NotSupportedException("Cannot set BoardSize on class B.");
    }
  }
}

If your code has a path where it may try to set BoardSize on an instance of B you should be prepared to handle that exception.

2) Only allow the derived class to set BoardSize:

class A
{
  public int BoardSize { get; protected set; }
}

class B : A
{
  public B()
  {
    BoardSize = 100;
  }
}

class C : A
{
  public void SetBoardSize(int boardSize)
  {
    BoardSize = boardSize;
  }
}


What you want is a new property in B that hides the one in A:

class B : A
{
    public new int BoardSize
    {
        get{return 100};
    }
}


See if this works:

class A
{
    public virtual int BoardSize { get; protected set; }
}


If it may be necessary for a derived class to change an outward-facing aspect of a member (e.g. change a property between read/write and read-only, or have a method in a derived-type return a more-derived type than a like-named method in the base type), then the member itself should be non-virtual, but its implementation should simply wrap a call to a protected virtual implementation. Derived types may shadow the base class's members that call the protected virtual implementation, but should not put meaningful logic there.

Thus:

class A
{
    public int BoardSize { get {return GetBoardSize(); set {SetBoardSize(value); }
    protected abstract int GetBoardSize();
    protected abstract void SetBoardSize(int newSize);
    public abstract bool IsResizable { get; }
}

class B : A
{
    public new int BoardSize { get {return GetBoardSize(); }
    protected override int GetBoardSize() { return 100; }
    protected override void SetBoardSize(int newSize)
        { throw new NotSupportedException("Board is not resizable."); }
    public override bool IsResizable { get {return false;} }
}

An attempt to set BoardSize on a variable of type B will fail at compile time on the basis that the property is read-only. Storing a reference to a B in a variable of type A and trying to set BoardSize on that will compile, but will throw an exception at runtime. The class should be documented to specify that code which wants to set BoardSize should be prepared for the fact that the board may not be resizable, and that if the caller code would be able to do something sensible in that case, it should check IsResizable before trying to set BoardSize.

0

精彩评论

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