2013-07-22 11 views
5

napisałem następującą aplikację konsoli do przetestowania właściwości statycznych:Jaki jest najlepszy sposób zdefiniowania właściwości statycznej zdefiniowanej raz w podklasie?

using System; 

namespace StaticPropertyTest 
{ 
    public abstract class BaseClass 
    { 
     public static int MyProperty { get; set; } 
    } 

    public class DerivedAlpha : BaseClass 
    { 
    } 

    public class DerivedBeta : BaseClass 
    { 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      DerivedBeta.MyProperty = 7; 
      Console.WriteLine(DerivedAlpha.MyProperty); // outputs 7 
     } 
    } 
} 

Ponieważ ta aplikacja konsola demonstruje właściwość MyProperty istnieje raz dla wszystkich wystąpień klasy bazowej. Czy istnieje wzorzec do zastosowania, który pozwoliłby mi zdefiniować właściwość statyczną, która będzie miała przypisaną pamięć dla każdego typu podklasy?

Biorąc pod uwagę powyższy przykład, chciałbym wszystkich wystąpień DerivedAlpha dzielić tę samą właściwość statyczna, a wszystkie instancje DerivedBeta udostępniania inny instancję obiektu statycznego.

Dlaczego próbuję to zrobić?

Leniwie inicjuję zbiór nazw właściwości klas z pewnymi atrybutami (poprzez odbicie). Nazwy właściwości będą identyczne dla każdej wyprowadzonej instancji klasy, więc wydaje się, że przechowywanie jej w każdej instancji klasy jest marnotrawstwem. Nie mogę uczynić go statycznym w klasie bazowej, ponieważ różne podklasy będą miały różne właściwości.

Nie chcę replikować kodu, który zapełnia kolekcję (poprzez odbicie) w każdej klasie pochodnej. Wiem, że jednym z możliwych rozwiązań jest zdefiniowanie metody zapełniania kolekcji w klasie bazowej i wywołanie jej z każdej klasy pochodnej, ale nie jest to najbardziej eleganckie rozwiązanie.

Update - Przykład tego, co robię

Na życzenie Jona, tutaj jest przykładem tego, co próbuję zrobić. Zasadniczo mogę opcjonalnie dekorować właściwości w moich klasach za pomocą atrybutu [SalesRelationship(SalesRelationshipRule.DoNotInclude)] (istnieją inne atrybuty, jest to tylko uproszczony przykład).

public class BaseEntity 
{ 
    // I want this property to be static but exist once per derived class. 
    public List<string> PropertiesWithDoNotInclude { get; set; } 

    public BaseEntity() 
    { 
     // Code here will populate PropertiesWithDoNotInclude with 
     // all properties in class marked with 
     // SalesRelationshipRule.DoNotInclude. 
     // 
     // I want this code to populate this property to run once per 
     // derived class type, and be stored statically but per class type. 
    } 
} 

public class FooEntity : BaseEntity 
{ 
    [SalesRelationship(SalesRelationshipRule.DoNotInclude)] 
    public int? Property_A { get; set; } 

    public int? Property_B { get; set; } 

    [SalesRelationship(SalesRelationshipRule.DoNotInclude)] 
    public int? Property_C { get; set; } 
} 

public class BarEntity : BaseEntity 
{ 
    public int? Property_D { get; set; } 

    [SalesRelationship(SalesRelationshipRule.DoNotInclude)] 
    public int? Property_E { get; set; } 

    public int? Property_F { get; set; } 
} 

Pożądany końcowy wynik

Dostęp FooEntity.PropertiesWithDoNotInclude zwraca List<string> od:

{ 
    "Property_A", 
    "Property_C" 
} 

Uzyskiwanie dostępu BarEntity.PropertiesWithDoNotInclude zwraca List<string> od:

{ 
    "Property_E" 
} 

Odpowiedz

4

Jon ma dobre rozwiązanie, jak zwykle, chociaż nie widzę, jakie dobre atrybuty robią tutaj, ponieważ muszą one być wyraźnie dodane do każdego podtypu i nie zachowują się jak właściwości.

Podejście Dictionary może zdecydowanie zadziałać. Oto kolejny sposób, aby to zrobić, co wyraźnie deklaruje, że będzie jedna zmienna za podklasa BaseEntity:

class FilteredProperties<T> where T : BaseEntity 
{ 
    static public List<string> Values { get; private set; } 
    // or static public readonly List<string> Values = new List<string>(); 
    static FilteredProperties() 
    { 
     // logic to populate the list goes here 
    } 
} 

Wadą jest to, że jest to raczej trudne do sparowania z GetType() rozmowy takie jak można wykorzystać w metodach z BaseEntity. A Dictionary, lub jego opakowanie, które implementuje populację leniwą, jest lepsze dla tego użycia.

+0

OP określił, że "Nazwy właściwości będą identyczne dla każdej wyprowadzonej instancji klasy" - co sugeruje, że jest to efektywna stała dla każdej klasy, co oznacza, że ​​może to być atrybut, który jest następnie pobierany przez odbicie. Nie, nie zachowuje się dokładnie tak jak własność - ale pozwala określić wartość dla klasy, a następnie pobrać tę wartość ... Teraz mamy więcej informacji w pytaniu, tym bardziej przejrzyste jest to, co OP robi, a słownik z 'Type' na * something * jest prawdopodobnie drogą do zrobienia. –

+0

Czy Twoje rozwiązanie ma wykorzystywać podejście singleton (według typu)? Jeśli tak, to mi się podoba - ale można to zrobić nieco rozszerzając. –

+0

@Jon: oops Brakowało mi słowa kluczowego 'static'. –

3

Dwa możliwe podejścia:

  • Użyj atrybutów; udekoruj każdą podklasę atrybutem, np.

    [MyProperty(5)] 
    public class DerivedAlpha 
    { 
    } 
    
    [MyProperty(10)] 
    public class DerivedBeta 
    { 
    } 
    

    Działa to tylko wtedy, gdy są faktycznie stałe.

  • używać słownika:

    var properties = new Dictionary<Type, int> 
    { 
        { typeof(DerivedAlpha), 5) }, 
        { typeof(DerivedBeta), 10) }, 
    }; 
    

EDIT: Teraz, gdy mamy więcej kontekstu, odpowiedź Bena jest naprawdę dobry, stosując sposób, że leki generyczne pracować w języku C#.To jest jak przykład słownika, ale z lenistwem, bezpieczeństwem wątków i prostym globalnym dostępem, wszystko wbudowane.

+0

Rozszerzyłem moją odpowiedź. – LeopardSkinPillBoxHat

+0

W twoim drugim przykładzie, masz na myśli "DerivedBeta" dla drugiego przedmiotu? :) –

+0

@ Chips_100: Naprawiono, dziękuję. –

0

Odpowiedź One:
Zastąp właściwość w każdej klasie za pomocą new int

public abstract class BaseClass 
{ 
    public static int MyProperty { get; set; } 
} 

public class DerivedAlpha : BaseClass 
{ 
    public static new int MyProperty { get; set; } // !! new int !! 
} 

public class DerivedBeta : BaseClass 
{ 
    public static new int MyProperty { get; set; } // !! new int !! 
} 

     DerivedAlpha.MyProperty = 7; 
     DerivedBeta.MyProperty = 8; 
     BaseClass.MyProperty = 9; 

odpowiedzieć na dwa:
wartości umieszczone w słowniku dla każdego typu

public abstract class BaseClass2<T> 
{ 
    public static Dictionary<Type, int> propertyStore = new Dictionary<Type, int>(); 

    public static int MyProperty 
    { 
     get 
     { 
      var t = typeof(T); 
      return propertyStore[t]; 
     } 

     set 
     { 
      var t = typeof(T); 
      propertyStore[t] = value; 
     } 
    } 
} 

public class DerivedAlpha2 : BaseClass2<DerivedAlpha2> 
{ 
} 

public class DerivedBeta2 : BaseClass2<DerivedBeta2> 
{ 
} 

     DerivedBeta2.MyProperty = 7; 
     DerivedAlpha2.MyProperty = 8; 
     // BaseClass2.MyProperty = 9; // does not compile