0

我有以下代码。

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

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

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

这怎么可能?

4

5 回答 5

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来实现您的目标,但这会在您的代码中引入严重的问题。
如果您无法更改A并且B需要从中派生,请A使用以下代码:

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

这与 .NET 框架是一致的。例如,ReadOnlyCollection在您调用时抛出此异常Add(在将其转换为 之后ICollection<T>)。

于 2011-05-10T11:27:56.827 回答
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;
  }
}
于 2011-05-10T11:31:20.580 回答
0

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

class B : A
{
    public new int BoardSize
    {
        get{return 100};
    }
}
于 2011-05-10T11:27:14.323 回答
0

看看这是否有效:

class A
{
    public virtual int BoardSize { get; protected set; }
}
于 2011-05-10T11:27:28.593 回答
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存储对 a 的引用并尝试在其上设置 BoardSize 将编译,但会在运行时引发异常。应记录该类以指定要设置的代码应针对板可能无法调整大小的事实做好准备,并且如果调用者代码在这种情况下能够做一些明智的事情,则应在尝试之前进行检查设置。BABoardSizeIsResizableBoardSize

于 2011-07-27T00:54:57.760 回答