如何将override属性限制为只读

时间:2011-05-10 11:24:33

标签: c# properties derived-class base-class

我有以下代码。

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

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

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

在基类中,属性是可读/写的。但是在派生类中它是readonly并且应该总是返回100.虽然当我运行代码时我发现它总是按预期返回100.

但是,我不希望客户在B类中设置BoardSize。所以它不应该允许客户端写 b.BoardSize = 55

怎么可能?

5 个答案:

答案 0 :(得分:5)

简短回答:嗯......你不能! 答案很长:
您可以使用BoardSize隐藏基类中new的实现:

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

这将使以下代码无效:

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

但这只会让事情变得更糟! 以下代码有效:

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

并打印

  

55
  100

结论:
您可以使用new来实现目标,但这会在您的代码中引入严重问题 如果您无法更改AB需要从A派生,请使用以下代码:

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

这与.NET框架一致。例如,ReadOnlyCollection在您致电Add(将其投放到ICollection<T>后)时会抛出此异常。

答案 1 :(得分:1)

您有两种选择。

1)在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.");
    }
  }
}

如果您的代码有一个路径,它可能会尝试在BoardSize的实例上设置B,那么您应该准备好处理该异常。

2)仅允许派生类设置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;
  }
}

答案 2 :(得分:0)

你想要的是B中的 new 属性,它隐藏了A中的一个:

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

答案 3 :(得分:0)

看看是否有效:

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

答案 4 :(得分:0)

如果派生类可能需要更改成员的外向方面(例如,更改读/写和只读之间的属性,或者派生类型中的方法返回更多派生类型比基类型中的类似命名的方法,然后成员本身应该是非虚拟的,但它的实现应该简单地包含对受保护的虚拟实现的调用。派生类型可能会影响调用受保护虚拟实现的基类成员,但不应该在那里放置有意义的逻辑。

因此:

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

尝试在BoardSize类型的变量上设置B将在编译时失败,因为该属性是只读的。在B类型的变量中存储对A的引用并尝试在其上设置BoardSize将进行编译,但会在运行时抛出异常。应记录该类,以指定想要设置BoardSize的代码应该为董事会可能无法调整大小的事实做好准备,并且如果调用者代码能够在这种情况下做一些合理的事情,那么在尝试设置IsResizable之前,应先检查BoardSize