2009-09-28 15 views
19

Chciałbym wymusić jedynie implementację pobierającego C# na danej właściwości z podstawowej abstrakcyjnej klasy. Klasy pochodne mogą, jeśli chcą, dostarczać także ustawiania dla tej właściwości do publicznego użytku typu statycznie związanego.Zastępowanie abstrakcyjnej właściwości tylko do odczytu dla odczytu/zapisu Właściwość

Biorąc pod uwagę następujące klasa abstrakcyjna:

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

Jeśli chcę klasę pochodnych, które również implementuje setter, mogę naiwnie spróbować:

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

    private int field; 
} 

Ale wtedy pojawia się błąd składni, odkąd spróbuj zastąpić nieistniejącego ustawiacza. Próbowałem w inny sposób, na przykład deklarując, że seter bazujący jest prywatny i taki, i wciąż natrafiam na wszelkiego rodzaju błędy, które uniemożliwiają mi to. Musi istnieć sposób, aby to zrobić, ponieważ nie narusza to żadnej umowy z klasą podstawową.

Nawiasem mówiąc, można to zrobić za pomocą interfejsów, ale naprawdę potrzebuję tej domyślnej implementacji.

Natknąłem się na tę sytuację tak często, zastanawiałem się, czy istnieje ukryta sztuczka składniowa C# do tego, inaczej po prostu będę z nią żyć i zaimplementuję ręczną metodę SetProperty().

+0

Cross-Link: http://stackoverflow.com/questions/2243886/make-a-read-only-property-writable-in-the-derived-class – Mikhail

Odpowiedz

11

Nie możesz tego zrobić bezpośrednio, ponieważ nie możesz new i override z tą samą sygnaturą tego samego typu; istnieją dwie możliwości - jeśli kontrolować klasę bazową, dodać sekund właściwość:

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

Else można wprowadzić dodatkowy poziom w hierarchii klasa:

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

Twoje rozwiązania są interesujące, będę rozważać trochę na nich. – Coincoin

+1

Twoje rozwiązanie jest najbliżej. Ale nie sądzę, że można to zrobić bez zmuszania wywodzącej się klasy do akrobatyki. – Coincoin

2

Co o czymś takim:

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

    protected abstract int GetProperty(); 
} 
+1

Każdy spadkobierca musi teraz zastąpić oba - nieco zbędny? –

+0

Tylko w przypadku przesłonięcia właściwości. Inaczej, bez wirtualnej własności, która mogłaby być faktycznie dopuszczalną alternatywą. – Coincoin

+1

Jeśli nie zastąpisz właściwości, cel zestawu jest bardzo ... nietypowy. –

1

Czy pasowałoby to do twoich potrzeb?

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 został usunięty, a wartość bazowa jest jeszcze tylko do przechowywania tej wartości. To powinno pokazać "5". I kompilator powinien zamieszanie o 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

Miałem podobny wymóg gdzie potrzebne interfejs, aby móc dzielić wspólną funkcjonalność sortowania pomiędzy dwoma luźno powiązanych klas. Jeden z nich miał własność Order-only Order, a druga posiadała właściwość Order-write, ale potrzebowałem sposobu, aby przeczytać tę samą informację z obu klas.

Okazuje się, że można to zrobić, ukrywając wartość tylko do odczytu w interfejsie pochodnym. Oto jak to zrobiłem.

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; 
    } 
} 
Powiązane problemy