如何使用C#中的setter覆盖仅限getter的属性?

更新此问题已经过修改,以使其更加清晰。 下面的答案似乎反映出这种方法效果很好。 希望这个问题可以帮助那些需要添加getset to existing property的人。


今天遇到一个问题,我需要用getset来覆盖基类的get -only属性。 目前的共识似乎是这是不可能的,但我认为我找到了一种方法。

一般的想法是创建一个new属性而不是直接override旧属性,然后我们创建一个桥接方法, override调用新的方法override旧的get方法。

情况

这是一些无法修改的任意预先存在的类型结构的代码。

 public abstract class A { public abstract int X { get; } } public class B : A { public override int X { get { return 0; } } } 

问题

我们想编写这段代码,但不会编译。

 public class C : B // won't compile: X can't have a 'set' method { private int _x; public override int X { get { return _x; } set { _x = value; } } } 

我们编写了我们想要的代码,但是我们将该属性声明为new而不是override ,允许我们声明一个set方法。

 public class D : C // Same thing, but will compile because X is 'new' { private int _x; public new virtual int X { get { return this._x; } set { this._x = value; } } // also 'virtual', unless we want to 'sealed' it. // Bridge method provides the override functionality: protected sealed override int XGetter { get { return this.X; } } // 'sealed' because this bridge should always refer to the new 'get' method } 

额外的桥接方法XGetter提供了override 。 这是使用中间层粘贴到基类结构:

 public abstract class C : B //abstract intermediate layer { // Override-and-seal the base property's getter. public sealed override int X { get { return this.XGetter; } } // Define the bridge property for the new class to override. protected abstract int XGetter { get; } } 

我认为D现在等同于inheritance自B的类,同时也能够在setter中覆盖。 它是否正确?

请注意您的解决方案,因为它隐藏了A和B的原始意图。尽管如此,您的解决方案确实有效,即使在转换为基类时也是如此。

例:

  D d = new D(); dX = 2; B b = d as B; Assert.AreEqual(2, bX); 

如果可以修改基类,我建议使用reflection。

更新:以下是不正确的。

没有。

 public abstract class A { public abstract int X { get; } public int GetXPlusOne() { return X + 1; } } 

您不会更改AX的值。

 var d = new D(); dX = 10; d.GetXPlusOne() == 1 

通过在您的示例中引入新属性XGetter,您已经使解决方案变得比它需要的更复杂。 您可以引入相同的属性,然后反转哪个属性获取getter和setter。

 public abstract class A { public abstract int X { get; } } public class D : A { private int _x; public sealed override int X { get { return XGetterSetter; } } public virtual int XGetterSetter { get { return this._x; } set { this._x = value; } } } 

在上面的示例中,D类中的代码与原始示例中的代码一样多。 这样就不需要你的例子中的B类和C类。

从语义上讲,这个解决方案可能不一样。 您必须设置XGetterSetter属性而不是X属性。 D的派生类也必须重写XGetterSetter而不是X.