Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

UPDATE: The following is INCORRECT.

No.

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

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

You won't change the value of A.X.

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. You can introduce the same property and just reverse which property gets the getter and 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. This just eliminates the need for class B and class C from your example.

Semantically, this solution may not be the same. You'd have to set the XGetterSetter property as opposed to the X property. Derived classes of D would also have to override XGetterSetter as opposed to X.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top