如何使用C#中的setter覆盖仅限getter的属性?
更新 :此问题已经过修改,以使其更加清晰。 下面的答案似乎反映出这种方法效果很好。 希望这个问题可以帮助那些需要添加get
或set
to existing property的人。
今天遇到一个问题,我需要用get
和set
来覆盖基类的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.