Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
755 views
in Technique[技术] by (71.8m points)

overriding - 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.


Ran into a problem today where I needed to override a base class's get-only property with both a get and set. 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 overrideing the old one, then we create a bridge method that overrides the old get method with a call to the new one.

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.

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. 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. Is this correct?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...