Подтвердить что ты не робот

Переопределить свойство readonly для чтения/записи

Я хотел бы только принудительно выполнить реализацию С# getter в заданном свойстве из базового абстрактного класса. Производные классы могут, если они захотят, также предоставить средство для этого свойства для публичного использования статически связанного типа.

Учитывая следующий абстрактный класс:

public abstract class Base
{
    public abstract int Property { get; }
}

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

public class Derived : Base
{
    public override int Property
    {
        get { return field; }
        set { field = value; } // Error : Nothing to override.
    } 

    private int field;
}

Но затем я получаю синтаксическую ошибку, так как я пытаюсь переопределить не существующий сеттер. Я попробовал другой способ, например, объявить базовый наборщик приватным и таким, и я все еще натыкаюсь на всевозможные ошибки, которые мешают мне это делать. Должен быть способ сделать это, поскольку он не нарушает какой-либо контракт с базовым классом.

Кстати, это можно сделать с помощью интерфейсов, но мне действительно нужна эта реализация по умолчанию.

Я так часто натыкался на эту ситуацию, мне было интересно, существует ли скрытый трюк синтаксиса С#, иначе я просто буду жить с ним и реализовать ручной метод SetProperty().

4b9b3361

Ответ 1

Вы не можете сделать это напрямую, так как вы не можете new и override с одной и той же сигнатурой того же типа; есть два варианта: если вы управляете базовым классом, добавьте второе свойство:

public abstract class Base
{
    public int Property { get { return PropertyImpl; } }
    protected abstract int PropertyImpl {get;}
}
public class Derived : Base
{
    public new int Property {get;set;}
    protected override int PropertyImpl
    {
        get { return Property; }
    }
}

Кроме того, вы можете ввести дополнительный уровень в иерархии классов:

public abstract class Base
{
    public abstract int Property { get; }
}
public abstract class SecondBase : Base
{
    public sealed override int Property
    {
        get { return PropertyImpl; }
    }
    protected abstract int PropertyImpl { get; }
}
public class Derived : SecondBase
{
    public new int Property { get; set; }

    protected override int PropertyImpl
    {
        get { return Property; }
    }
}

Ответ 2

Что-то вроде:

public abstract class Base
{
    public virtual int Property
    {
        get { return this.GetProperty(); }
        set { }
    }

    protected abstract int GetProperty();
}

Ответ 3

Соответствует ли это вашим потребностям?

public abstract class TheBase
{
    public int Value
    {
        get;
        protected set;
    }
}
public class TheDerived : TheBase
{
    public new int Value
    {
        get { return base.Value; }
        set { base.Value = value; }
    }
}

virtual был удален, но базовое значение остается единственным хранилищем для значения. Таким образом, это должно показать "5". И компилятор должен беспокоиться о b.Value = 4;

TheDerived d = new TheDerived();
d.Value = 5;
TheBase b = d;
//b.Value = 4;    // uncomment for compiler error
cout << "b.Value == " << b.Value << endl;

-Jesse

Ответ 4

У меня было аналогичное требование, когда мне нужен интерфейс, чтобы иметь возможность совместно использовать общие функции сортировки между двумя слабо связанными классами. Один из них имел свойство "Только для чтения", а у другого - свойство Order-Write для чтения-записи, но мне нужен был способ прочитать свойство таким же образом из обоих классов.

Оказывается, это можно сделать, спрятав значение только для чтения в производном интерфейсе. Вот как я это сделал.

interface ISortable
{
    int Order { get; }
}

interface ISortableClass2
    : ISortable
{
    // This hides the read-only member of ISortable but still satisfies the contract
    new int Order { get; set; }
}

class SortableClass1
    : ISortable
{
    private readonly int order;

    public SortableClass1(int order)
    {
        this.order = order;
    }

    #region ISortable Members

    public int Order
    {
        get { return this.order; }
    }

    #endregion
}

class SortableClass2
    : ISortableClass2
{
    #region ISortableClass2 Members

        public int Order { get; set; } 

    #endregion
}

class RunSorting
{
    public static void Run()
    {
        // Test SortableClass1
        var list1 = new List<SortableClass1>();

        list1.Add(new SortableClass1(6));
        list1.Add(new SortableClass1(1));
        list1.Add(new SortableClass1(5));
        list1.Add(new SortableClass1(2));
        list1.Add(new SortableClass1(4));
        list1.Add(new SortableClass1(3));

        var sorted1 = SortObjects(list1);

        foreach (var item in sorted1)
        {
            Console.WriteLine("SortableClass1 order " + item.Order);
        }

        // Test SortableClass2
        var list2 = new List<SortableClass2>();

        list2.Add(new SortableClass2() { Order = 6 });
        list2.Add(new SortableClass2() { Order = 2 });
        list2.Add(new SortableClass2() { Order = 5 });
        list2.Add(new SortableClass2() { Order = 1 });
        list2.Add(new SortableClass2() { Order = 4 });
        list2.Add(new SortableClass2() { Order = 3 });

        var sorted2 = SortObjects(list2);

        foreach (var item in sorted2)
        {
            Console.WriteLine("SortableClass2 order " + item.Order);
        }
    }

    private static IEnumerable<T> SortObjects<T>(IList<T> objectsToSort) where T : ISortable
    {
        if (objectsToSort.Any(x => x.Order != 0))
        {
            return objectsToSort.OrderBy(x => x.Order);
        }

        return objectsToSort;
    }
}