W C #
Czy istnieje sposób na przekształcenie właściwości automatycznej w leniwie ładowaną właściwość automatyczną z określoną wartością domyślną?
Zasadniczo próbuję to zmienić ...
private string _SomeVariable
public string SomeVariable
{
get
{
if(_SomeVariable == null)
{
_SomeVariable = SomeClass.IOnlyWantToCallYouOnce();
}
return _SomeVariable;
}
}
w coś innego, gdzie mogę określić domyślne, a resztę zajmie się automatycznie ...
[SetUsing(SomeClass.IOnlyWantToCallYouOnce())]
public string SomeVariable {get; private set;}
c#
automatic-properties
ctorx
źródło
źródło
Odpowiedzi:
Nie, nie ma. Właściwości zaimplementowane automatycznie służą tylko do zaimplementowania najbardziej podstawowych właściwości: pola zapasowego z funkcją pobierającą i ustawiającą. Nie obsługuje tego typu dostosowywania.
Możesz jednak użyć
Lazy<T>
typu 4.0, aby utworzyć ten wzorzecTen kod leniwie obliczy wartość
_someVariable
przy pierwszymValue
wywołaniu wyrażenia. Zostanie obliczona tylko raz i zapisuje wartość do przyszłego wykorzystaniaValue
nieruchomościźródło
SomeClass.IOnlyWantToCallYouOnce
w Twoim przykładzie musi być statyczny, aby można go było używać z inicjatorem pola.Prawdopodobnie najbardziej zwięzłym, jaki można uzyskać, jest użycie operatora koalescencji zerowej:
źródło
IOnlyWantToCallYouOnce
zwrotównull
będzie to wywoływać więcej niż raz._SomeVariable ?? ( _SomeVariable = SomeClass.IOnlyWantToCallYouOnce() );
- zwróć uwagę na dodanie nawiasów wokół ustawienia,_SomeVariable
jeśli jest puste.Lazy<>
, ale dla naszych celów to działało lepiej. W najnowszym C # można to również napisać jeszcze bardziej zwięźle.=> _SomeVariable ?? (_SomeVariable = SomeClass.IOnlyWantToCallYouOnce());
Niektórzy mogą nie zauważyć na pierwszy rzut oka, że operator ocenia prawostronny operand i zwraca jego wynik .W C # 6 jest nowa funkcja o nazwie Expression Bodied Auto-Properties , która pozwala napisać ją nieco bardziej czytelnie:
Można teraz zapisać jako:
źródło
IOnlyWantToCallYouOnce
byłaby wywoływana podczas konstruowania za każdym razem, gdy tworzona jest instancja klasy.SomeVariable
jest leniwy.Nie tak, parametry atrybutów muszą mieć stałą wartość, nie można wywołać kodu (nawet kodu statycznego).
Możesz jednak być w stanie zaimplementować coś z aspektami PostSharp.
Sprawdź je:
PostSharp
źródło
Oto moja implementacja rozwiązania Twojego problemu. Zasadniczo idea jest właściwością, która zostanie ustawiona przez funkcję przy pierwszym dostępie, a kolejne dostępy przyniosą tę samą wartość zwracaną co pierwszy.
Następnie do użycia:
Jest oczywiście narzut związany z przekazywaniem wskaźnika funkcji dookoła, ale robi to za mnie i nie zauważam zbyt dużego narzutu w porównaniu z powtarzaniem metody.
źródło
Jestem wielkim fanem tego pomysłu i chciałbym zaoferować następujący fragment kodu C #, który nazwałem proplazy.snippet. (Możesz go zaimportować lub wkleić do standardowego folderu, który możesz pobrać z Menedżera fragmentów)
Oto próbka jego wyników:
Oto zawartość pliku fragmentu: (zapisz jako proplazy.snippet)
źródło
Nie sądzę, że jest to możliwe w czystym języku C #. Ale możesz to zrobić za pomocą narzędzia do ponownego zapisywania IL, takiego jak PostSharp . Na przykład pozwala na dodawanie programów obsługi przed i po funkcjach w zależności od atrybutów.
źródło
Operator ?? = jest dostępny w języku C # 8.0 i nowszych, więc możesz teraz zrobić to jeszcze bardziej zwięźle:
źródło
Zrobiłem to tak:
a później możesz go używać jak
źródło
public ISet<String> RegularProperty {get;set} public string CalculatedProperty => this.LazyValue(() => { return string.Join(",", RegularProperty.ToArray()); });
https://github.com/bcuff/AutoLazy używa Fody, aby dać ci coś takiego
źródło
i wołam jak poniżej
źródło
Jeśli używasz konstruktora podczas leniwej inicjalizacji, poniższe rozszerzenia mogą być również pomocne
Stosowanie
źródło
LazyInitializer.EnsureInitialized()
? Ponieważ z tego, co wiem, oprócz funkcji powyżejLazyInitializer
zapewnia obsługę błędów, a także funkcjonalność synchronizacji. Kod źródłowy LazyInitializer .