2009-09-07 7 views
10

Mam pewien kod automatycznej instancji, który chciałbym zastosować do około 15 właściwości w dość dużej klasie. Kod jest podobny do następującego ale typ różni dla każdego wystąpienia:Ekwiwalent C# dla makr C++ i użycie Auto <> Właściwości

protected ComplexType _propertyName; 
public ComplexType PropertyName 
{ 
    get 
    { 
     if (_propertyName == null) { 
      _propertyName = new ComplexType(); 
     } 

     return _propertyName; 
    } 
} 

powtórzyć tę C++ (jak jest ~ 15 przypadki), to, że nie używane preprocesor makro ale I powiadomienie C# nie obsługuje ich.

Zastanawiam się, czy ktoś ma zalecenie, jak to zrobić w sposób czysty w C#?

Odpowiedz

22

Może to zrobić rzeczy trochę neater można dodać tej metody, aby wprowadzić pewne ponownego użycia:

protected ComplexType _propertyName; 
public ComplexType PropertyName 
{ 
    get 
    { 
     return GetProperty(ref _propertyName); 
    } 
} 
. 
. 
private T GetProperty<T>(ref T property) where T : new() 
{ 
    if (property == null) 
    property = new T(); 
    return property; 
} 
6

Nawet jeśli bezpośrednio nie rozwiąże problemu, można przyjrzeć się nowej klasy Lazy<T> który jest dostarczany z .NET 4.0. Jest specjalnie zaprojektowany do leniwych scenariuszy inicjalizacji.

16

Można użyć operatora ?? uproszczenie kodu w jednej linii:

protected ComplexType _propertyName; 
public ComplexType PropertyName 
{ 
    get 
    { 
    return _propertyName ?? (_propertyName = new ComplexType()); 
    } 
} 

marginesie pewnie bym uniknąć pól chronionych. Jeśli musisz ustawić właściwość z klasy pochodnej, wolałabym utworzyć chronionego ustawiacza.

+1

Z mojego doświadczenia w C++, ogólnie uważam, że ustawienie wszystkiego jako "chronionego" nad "prywatnym" jest lepszym posunięciem, jeśli chcesz zachować swoją aplikację w przyszłości, nie rezygnując z ochrony członków. Rzadko używam prywatnego. – Ryall

+2

@Kelix: Ale faktycznie rezygnujesz z ochrony użytkowników, zabezpieczając pola. Teraz każda klasa pochodna ma pełny dostęp do twoich pól.Jest to trochę podobne do posiadania pól publicznych, z tym wyjątkiem, że tylko klasy pochodne i nie wszystkie klasy mają dostęp do pól. –

+0

@Martin: Tak, to jest pożądany efekt. Jeśli wyraźnie nie chcę zezwolić na dostęp w klasach pochodnych, zaznaczę to jako "chronione". Ogólnie rzecz biorąc, jeśli masz zamiar podjąć wysiłek wyprowadzenia klasy, będziesz chciał w jakiś sposób dodać lub zmienić zachowanie, więc dlaczego nie zapewnić nieograniczonego dostępu do tego? Oczywiście, gdyby był to ogólnodostępny interfejs (taki jak biblioteka klasy), wówczas "prywatny" byłby znacznie lepiej dopasowany. Po prostu nie lubię ograniczać dostępu tam, gdzie nie jest to konieczne. – Ryall

11

Można zrobić rodzajowe struct, który obsługuje leniwy utworzenia:

public struct LazyCreate<T> where T : class, new() { 
    private T _value; 
    public T Value { 
     get { 
     if (_value == null) { 
      _value = new T(); 
     } 
     return _value; 
     } 
    } 
} 

protected LazyCreate<ComplexType> _propertyName; 
public ComplexType PropertyName { 
    get { 
     return _propertyName.Value; 
    } 
} 
+1

Chciałbym użyć przy użyciu ogólnej struktury, aby uniknąć posiadania więcej obiektów utworzonych na stercie. –

+0

Co się stanie, gdy T jest strukturą? new() nie wyklucza tego, a struktura AFAIK nie może być pusta. :) – Rytmis

+0

@Rytmis: Aby obsłużyć struktury, musiałby mieć oddzielną flagę, która wskazywałaby, czy wartość została utworzona, czy też nie, jednak leniwy sposób inicjalizacji dla struktur wydaje się ogólnie zły wybór projektu ... Dodam do tego ograniczenie że można go używać tylko z typami referencyjnymi. – Guffa

2

można użyć znacznie pomijane T4 (szablon tekst Transformation Toolkit) do generowania kodu. Jest ono zawarte z Visual Studio 2008.

Było 2009-06 .NET Rocks epizod o tym: "Peter Vogel uses Code Generation".

0

spróbuje użyć Hashtable lub słownika korzystał < ciąg, complexType > do grupy wszystkie właściwości. Coś takiego:

protected Dictionaty<string, ComplexType> _properties = new Dictionaty<string, ComplexType>(); 
public ComplexType Property(string name) 
{ 
    get 
    { 
     if (!properties.ContainsKey(name)) 
      _properties[name] = new ComplexType(); 

     return __properties[name]; 
    } 
} 
1

Można wdrożyć leniwe inicjowanie w sposób podobny do tego:

public class Lazy<T> where T : new() 
    { 
     private T _value; 
     private bool _isInitialized; 

     private T GetValue() 
     { 
      if (!_isInitialized) 
      { 
       _value = new T(); 
       _isInitialized = true; 
      } 

      return _value; 
     } 

     public static implicit operator T (Lazy<T> t) 
     { 
      return t.GetValue(); 
     } 
    } 

które pozwalają pisać kod tak:

 private Lazy<ComplexType> _lazyCt = new Lazy<ComplexType>(); 
     public ComplexType LazyCt 
     { 
      get { return _lazyCt; } 
     } 

Specyfika Inicjalizacja jest nieistotna, napisałem to tak, aby pokazać, że można ją przekształcić w przejrzysty sposób w niezaplanowaną wersję i przeprowadzić inicjalizację przy pierwszej konwersji. :)