2009-09-28 4 views
19

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

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

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

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

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

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

+0

Перекрестная ссылка: http://stackoverflow.com/questions/2243886/make-a-read-only-property-writable-in-the-derived-class – Mikhail

ответ

11

Вы не можете сделать это напрямую, так как вы не можете 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; } 
    } 
} 
+0

Ваши решения интересны, я буду размышлять немного на них. – Coincoin

+1

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

2

А что-то вроде:

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

    protected abstract int GetProperty(); 
} 
+1

Любое наследство теперь должно переопределить оба из них - немного избыточно? –

+0

Только при переопределении свойства. Иначе, без виртуального имущества, которое действительно может быть приемлемой альтернативой. – Coincoin

+1

Если вы не переопределяете свойство, цель набора очень ... необычна. –

1

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

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

1

У меня было подобное требование, где мне нужно интерфейс, чтобы иметь возможность разделить общую функциональность сортировки между двумя слабо связанными классами. Один из них имел свойство «Только для чтения», а у другого было свойство 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; 
    } 
}