简体   繁体   English

如何在 C# 中使用 setter 覆盖 getter-only 属性?

[英]How to override a getter-only property with a setter in C#?

Update : This question has been revised to make it clearer.更新这个问题已经过修改以使其更清楚。 The answers below seem to reflect that this method works well.下面的答案似乎反映了这种方法效果很好。 Hopefully this question can help people who need to add a get or set to an existing property.希望这个问题可以帮助需要向现有属性添加getset的人。


Ran into a problem today where I needed to override a base class's get -only property with both a get and set .今天遇到一个问题,我需要用getset覆盖基类的get -only 属性。 Current consensus seems to be that this is impossible, but I think that I found a method.目前的共识似乎是这是不可能的,但我认为我找到了一种方法。

The general idea is to make a new property instead of directly override ing the old one, then we create a bridge method that override s the old get method with a call to the new one.一般的想法是创建一个new属性而不是直接override旧的,然后我们创建一个桥接方法, override调用新的来override旧的get方法。

Situation情况

Here's some code for an arbitrary pre-existing type structure that can't be modified.这是无法修改的任意预先存在的类型结构的一些代码。

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

Problem问题

We'd like to write this code, but it won't compile.我们想编写这段代码,但它无法编译。

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

Solution解决方案

We write the code we want anyway, but we declare the property to be new instead of override , allowing us to declare a set method.我们无论如何都要编写我们想要的代码,但是我们将属性声明为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
}

The extra bridge method, XGetter , provides the override .额外的桥接方法XGetter提供了override This is glued to the base class structure using an intermediate layer:这使用中间层粘在基类结构上:

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

I think that D is now equivalent to a class inheriting from B while also being able to override in a setter.我认为D现在等效于从B继承的类,同时还可以在 setter 中覆盖。 Is this correct?这样对吗?

Be careful with your solution as it hides the original intent for A and B. That being said, your solution does work, even when casting to base classes.请注意您的解决方案,因为它隐藏了 A 和 B 的原始意图。话虽如此,您的解决方案确实有效,即使在转换为基类时也是如此。

Example:例子:

D d = new D();
d.X = 2;
B b = d as B;

Assert.AreEqual(2, b.X);

If the base classes can be modified, I recommend using reflection.如果可以修改基类,我建议使用反射。

UPDATE: The following is INCORRECT . UPDATE:下列哪项不正确

No.不。

public abstract class A
{
    public abstract int X { get; }

    public int GetXPlusOne()
    {
        return X + 1;
    }
}

You won't change the value of AX .您不会更改AX的值。

var d = new D();
d.X = 10;

d.GetXPlusOne() == 1

By introducing the new property XGetter in your example, you've made the solution more complex than it needs to be.通过在您的示例中引入新属性 XGetter,您使解决方案变得比需要的更复杂。 You can introduce the same property and just reverse which property gets the getter and setter.您可以引入相同的属性,只需反转哪个属性获得 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; } }
}

There's just as much code in class D in the above example as there is in your original example.上面示例中 D 类中的代码与原始示例中的代码一样多。 This just eliminates the need for class B and class C from your example.这只是从您的示例中消除了对 B 类和 C 类的需要。

Semantically, this solution may not be the same.在语义上,这个解决方案可能不一样。 You'd have to set the XGetterSetter property as opposed to the X property.您必须设置 XGetterSetter 属性而不是 X 属性。 Derived classes of D would also have to override XGetterSetter as opposed to X. D 的派生类也必须覆盖 XGetterSetter,而不是 X。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM