2011-01-06 26 views
8

Obecnie zmieniam powszechnie używaną klasę, aby przenieść tak dużo kosztownej inicjalizacji z konstruktora klasy do właściwości Lazy Initialized. Poniżej znajduje się przykład (w C#):Metody inicjalizacji Lazy z właściwościami

Przed:

public class ClassA 
{ 
    public readonly ClassB B; 

    public void ClassA() 
    { 
     B = new ClassB(); 
    } 
} 

Po:

public class ClassA 
{ 
    private ClassB _b; 

    public ClassB B 
    { 
     get 
     { 
      if (_b == null) 
      { 
       _b = new ClassB(); 
      } 

      return _b; 
     } 
    } 
} 

Istnieje uzasadniona niewiele więcej z tych właściwości w klasie mam zmienianie, a niektóre nie są używane w pewnych kontekstach (stąd lenistwo), ale jeśli zostaną użyte, prawdopodobnie będą wywoływane wielokrotnie.

Niestety, właściwości są często używane również w klasie. Oznacza to, że istnieje możliwość użycia zmiennej prywatnej (_b) bezpośrednio przez metodę bez jej zainicjowania.

Czy istnieje sposób udostępnienia tylko klasy publicznej (B) w klasie, a nawet alternatywnej metody z tą samą wartością inicjowaną, kiedy jest potrzebna?

to zamieszczać Od programistów (nie wystarczy prywatną podobno): https://softwareengineering.stackexchange.com/questions/34270/best-methods-for-lazy-initialization-with-properties

+0

@chibacity: Dzięki za retag –

Odpowiedz

6

Można rozważyć przeniesienie leniwych właściwości do klasy bazowej, aby uniknąć bezpośredniego dostępu do zmiennej bazowej. Nie idealna, którą znam. Zawsze myślałem, że to coś brakuje w C#, tj. Bezpośrednie wsparcie dla leniwych właściwości.

+0

Byłoby miło, gdyby można było zaimplementować właściwość, która sprawi, że będzie leniwy, aby usunąć wszystkie te potrzeby i mieć domy leniwą ładowaną właściwość bez konieczności odwoływania się do .Value. – BenAlabaster

+0

@BenAlabaster Kiedy po raz pierwszy zobaczyłem właściwości automatyczne, pomyślałem, że dodali leniwą funkcję - niestety nie. Byłoby wspaniale móc zdefiniować właściwość automatyczną z funkcją inicjalizatora. –

+0

@chibacity ciekawa myśl, zastanawiam się, czy byłoby to możliwe ... czas zacząć grać;) – BenAlabaster

16

Cóż, mój zalecanym rozwiązaniem byłoby powiedzieć współpracownika do korzystania z nieruchomości, a nie na polu. Ale możesz to do pewnego stopnia udowodnić:

public class ClassA 
{ 
    private Lazy<ClassB> _b = new Lazy<ClassB>(() => new ClassB()); 

    public ClassB B 
    { 
     get 
     { 
      return _b.Value; 
     } 
    } 
} 

Teraz trudno jest zepsuć.

+0

+1. Właśnie to miałem właśnie zasugerować. –

+0

Czym dokładnie jest "Lazy " w tym przykładzie? Dzięki. –

+0

Miło, nie byłem świadomy klasy Lazy ; jednak wydaje się nowy w 4, nie jest pewien, co używa OP. –

3

@chibacity opublikował (a następnie) usunął [i później niewyblakł: P] alternatywną opcję przy użyciu abstrakcyjnej klasy bazowej. Chociaż nie jest to idealne rozwiązanie pod względem dystrybucji kodu, zapewnia ono przyjemną enkapsulację, usuwając wiele bałaganu w kodzie, czyniąc czystsze i bardziej zwięzłe ClassA. Na przykład, można rozważyć połączenie techniki, aby osiągnąć oba cele:

public class ClassB { /* Class to be lazily instantiated */ } 

public abstract class BaseA 
{ 
    private Lazy<ClassB> _b = new Lazy<ClassB>(() => new ClassB()); 
    public virtual ClassB B { get { return _b.Value; } } 
} 

public class ClassA : BaseA 
{ 
    public override ClassB B { get { return base.B; } } 
} 

na pierwszy rzut oka wydaje się, że jest to bardziej długo zdyszany, ale jeśli wziąć pod uwagę, że ClassA który jest klasą byś pracować i Oznacza to, że wszystkie twoje referencje przechodzą przez tę samą właściwość - nie ma zbędnego zbędnego pola, co może spowodować zamieszanie, nie ma możliwości ominięcia nieruchomości, aby bezpośrednio odwoływać się do _b, i nie trzeba mówić swojemu współpracownikowi, z czego skorzystać ... tylko jeden.

Nie twierdząc, że jest to właściwy sposób, lub że jest to wzorzec, który powinien, ale nie powinien być przestrzegany, po prostu wskazuję na zalety tego, co sugerował @chibacity, co w przeciwnym razie może pozostać niezauważone.

Byłoby miło, gdyby można było mieć domy leniwy załadowane właściwości bez konieczności odwoływania się do B.Value ...na przykład:

[Lazy] 
public ClassB B { get; } 

lub do obiektów bez konstruktorów bez parametrów

[Lazy(() => new ClassB("Hello", "World"))] 
public ClassB B { get; } 

czy może jako @chibacity sugerowane w komentarzu

public ClassB B { lazyget; } 

lub

public ClassB B { lazyget : new ClassB(); } 

Alas, I nie myśl o żadnym z nich se są obecnie dostępnymi rozwiązaniami w dowolnej formie ...

+0

Podobają mi się składnia z func i atrybutem, ale niestety argumenty atrybutów muszą być stałe w czasie kompilacji, więc to jest poza - wygląda jednak całkiem fajnie. :) –

+0

@chibacity To jest jedna rzecz, której zawsze jestem świadomy, kiedy piszę API - jak mam wyglądać składnia, kiedy to nazywam lub używam tej funkcji? Zazwyczaj projektuję to, co chcę, aby moje połączenia wyglądały, zanim zaprojektuję API, aby wszystko było po prostu. – BenAlabaster

Powiązane problemy