Как переопределить свойство getter только с установщиком в С#?

Обновление: Этот вопрос был изменен, чтобы сделать его более ясным. Ниже приведенные ответы отражают, что этот метод работает хорошо. Надеюсь, этот вопрос может помочь людям, которым необходимо добавить get или set к существующему свойству.


В настоящее время возникает проблема, когда мне нужно переопределить свойство базового класса get -only как с get, так и с set. Похоже, что нынешний консенсус заключается в том, что это невозможно, но я считаю, что нашел метод.

Общая идея состоит в том, чтобы создать свойство new вместо прямого 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 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 теперь эквивалентен классу, наследующему от B, а также может переопределять в сеттере. Правильно ли это?

Ответ 1

Будьте осторожны с вашим решением, поскольку оно скрывает первоначальные намерения для A и B. Это говорит о том, что ваше решение действительно работает, даже при использовании в базовых классах.

Пример:

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

        Assert.AreEqual(2, b.X);

Если базовые классы могут быть изменены, я рекомендую использовать отражение.

Ответ 2

UPDATE: Следующее является НЕПРАВИЛЬНЫМ.

Нет.

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

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

Вы не измените значение A.X.

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

d.GetXPlusOne() == 1

Ответ 3

Представляя новое свойство XGetter в вашем примере, вы сделали решение более сложным, чем это должно быть. Вы можете ввести одно и то же свойство и просто изменить, какое свойство получает получатель и сеттер.

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.