Jakie są korzyści z zadeklarowania zmiennej składowej jako tylko do odczytu? Czy to po prostu chroni przed zmianą wartości przez kogoś w trakcie cyklu życia klasy, czy też użycie tego słowa kluczowego powoduje poprawę szybkości lub wydajności?
295
readonly
pola typów struktur nakładają karę wydajności w porównaniu z polami zmiennymi, które po prostu nie są zmutowane, ponieważ wywołanie dowolnego elementureadonly
pola typu wartości spowoduje, że kompilator utworzy kopię pola i wywoła metodę członek na ten temat.Odpowiedzi:
Słowo
readonly
kluczowe służy do deklarowania stałej zmiennej składowej, ale umożliwia obliczenie wartości w czasie wykonywania. Różni się to od stałej zadeklarowanej za pomocąconst
modyfikatora, której wartość musi być ustawiona w czasie kompilacji. Za pomocąreadonly
można ustawić wartość pola w deklaracji lub w konstruktorze obiektu, którego pole jest członkiem.Użyj go również, jeśli nie chcesz ponownie kompilować zewnętrznych bibliotek DLL, które odwołują się do stałej (ponieważ jest ona zastępowana w czasie kompilacji).
źródło
Nie sądzę, aby przy użyciu pola „tylko do odczytu” można było poprawić wydajność. Jest to po prostu sprawdzenie, czy po ukończeniu budowy obiektu nie można wskazać nowej wartości w tym polu.
Jednak „tylko do odczytu” bardzo różni się od innych typów semantyki tylko do odczytu, ponieważ jest egzekwowane w czasie wykonywania przez CLR. Słowo kluczowe readonly jest kompilowane do .initonly, co jest weryfikowalne przez CLR.
Prawdziwą zaletą tego słowa kluczowego jest generowanie niezmiennych struktur danych. Niezmienne struktury danych z definicji nie mogą być zmieniane po zbudowaniu. Ułatwia to rozumowanie zachowania struktury w czasie wykonywania. Na przykład nie ma niebezpieczeństwa przekazania niezmiennej struktury do innej losowej części kodu. Nie mogą tego nigdy zmienić, więc możesz niezawodnie programować w oparciu o tę strukturę.
Oto dobry wpis na temat jednej z korzyści niezmienności: gwintowanie
źródło
Nie ma widocznych korzyści w zakresie wydajności
readonly
, a przynajmniej takich, o których nigdzie nie wspominałem. Służy to do robienia dokładnie tego, co sugerujesz, do zapobiegania modyfikacjom po ich zainicjowaniu.Jest to więc korzystne, ponieważ pomaga pisać bardziej niezawodny, bardziej czytelny kod. Prawdziwa korzyść z takich rzeczy pojawia się, gdy pracujesz w zespole lub w celu konserwacji. Deklarowanie czegoś
readonly
podobnego do zawarcia w kodzie umowy dotyczącej użycia tej zmiennej. Pomyśl o tym jako o dodawaniu dokumentacji w taki sam sposób, jak innych słowach kluczowych, takich jakinternal
lubprivate
, mówisz „ta zmienna nie powinna być modyfikowana po inicjalizacji”, a ponadto wymuszasz ją.Jeśli więc utworzysz klasę i oznaczysz niektóre zmienne składowe
readonly
według projektu, to zapobiegniesz popełnieniu błędu przez siebie lub innego członka zespołu, gdy będą one rozszerzać lub modyfikować twoją klasę. Moim zdaniem jest to korzyść, którą warto mieć (niewielkim kosztem dodatkowej złożoności językowej, o czym doofledorfer wspomina w komentarzach).źródło
Mówiąc bardzo praktycznie:
Jeśli użyjesz const w dll A i dll B odwołuje się do tej const, wartość tej const zostanie skompilowana do dll B. Jeśli ponownie wdrożysz dll A z nową wartością dla tej const, dll B nadal będzie używać oryginalnej wartości.
Jeśli użyjesz tylko do odczytu w bibliotekach dll A i dll B, które tylko do odczytu, to readonly zawsze będzie sprawdzane w czasie wykonywania. Oznacza to, że jeśli wdrożysz dll A z nową wartością tylko do odczytu, dll B użyje tej nowej wartości.
źródło
const
może mieć wzrost wydajnościreadonly
. Oto nieco głębsze objaśnienie z kodem: dotnetperls.com/readonlyreadonly
polach. Nie można zapisaćnew object();
w a,const
a to ma sens, ponieważ nie można upiec przedmiotów innych niż wartości, takich jak odwołania do innych zestawów podczas kompilacji bez zmiany tożsamości.Istnieje potencjalny przypadek, w którym kompilator może przeprowadzić optymalizację wydajności w oparciu o obecność słowa kluczowego tylko do odczytu.
Ma to zastosowanie tylko wtedy, gdy pole tylko do odczytu jest również oznaczone jako statyczne . W takim przypadku kompilator JIT może założyć, że to pole statyczne nigdy się nie zmieni. Kompilator JIT może wziąć to pod uwagę podczas kompilacji metod klasy.
Typowy przykład: twoja klasa może mieć statyczne pole tylko do odczytu IsDebugLoggingEnabled, które jest inicjowane w konstruktorze (np. Na podstawie pliku konfiguracyjnego). Po skompilowaniu rzeczywistych metod JIT kompilator może pominąć całe części kodu, gdy rejestrowanie debugowania nie jest włączone.
Nie sprawdziłem, czy ta optymalizacja jest faktycznie zaimplementowana w bieżącej wersji kompilatora JIT, więc to tylko spekulacja.
źródło
Pamiętaj, że tylko do odczytu odnosi się tylko do samej wartości, więc jeśli używasz typu odwołania, tylko chroni tylko odniesienie przed zmianą. Stan instancji nie jest chroniony przez readonly.
źródło
Nie zapomnij o obejściu tego problemu
readonly
ustawić pola poza konstruktorami używającymi parametrówout
.Trochę bałagan, ale:
Dalsza dyskusja tutaj: http://www.adamjamesnaylor.com/2013/01/23/Setting-Readonly-Fields-From-Chained-Constructors.aspx
źródło
out
..Zaskakujące, że tylko do odczytu może faktycznie spowodować wolniejszy kod, jak stwierdził Jon Skeet podczas testowania swojej biblioteki Noda Time. W takim przypadku test, który trwał 20 sekund, trwał tylko 4 sekundy po usunięciu readonly.
https://codeblog.jonskeet.uk/2014/07/16/micro-optimization-the-surishing-inefficiency-of-readonly-fields/
źródło
readonly struct
C # 7.2, korzyść z tego, że pole jest nie tylko do odczytu, znika.Jeśli masz wstępnie zdefiniowaną lub wstępnie obliczoną wartość, która musi pozostać taka sama przez cały program, powinieneś użyć stałej, ale jeśli masz wartość, którą należy podać w czasie wykonywania, ale po przypisaniu powinna pozostać taka sama w całym programie, powinieneś użyć tylko czytać. na przykład, jeśli musisz przypisać czas rozpoczęcia programu lub musisz zapisać wartość podaną przez użytkownika przy inicjalizacji obiektu i musisz ograniczyć ją przed dalszymi zmianami, powinieneś używać tylko do odczytu.
źródło
Dodanie podstawowego aspektu odpowiedzi na to pytanie:
Właściwości można wyrazić tylko do odczytu, pomijając
set
operatora. W większości przypadków nie trzeba dodawaćreadonly
słowa kluczowego do właściwości:W przeciwieństwie do tego: pola potrzebują
readonly
słowa kluczowego, aby osiągnąć podobny efekt:Tak więc jedną zaletą oznaczenia pola, która
readonly
może być osiągnięcie podobnego poziomu ochrony przed zapisem jako właściwość bezset
operatora - bez konieczności zmiany pola na właściwość, jeśli z jakiegokolwiek powodu jest to pożądane.źródło
Uważaj na prywatne tablice tylko do odczytu. Jeśli zostaną one ujawnione klientowi jako obiektowi (możesz to zrobić dla interfejsu COM tak jak ja) klient może manipulować wartościami tablic. Użyj metody Clone () podczas zwracania tablicy jako obiektu.
źródło
ReadOnlyCollection<T>
zamiast tablicy.ImmutableArray<T>
, co pozwala uniknąć tworzenia boksu do interfejsu (IReadOnlyList<T>
) lub zawijania w klasie (ReadOnlyCollection
). Ma wydajność porównywalną do macierzy rodzimych: blogs.msdn.microsoft.com/dotnet/2013/06/24/…WPF może przynosić korzyści w zakresie wydajności, ponieważ eliminuje potrzebę kosztownych DependencyProperties. Może to być szczególnie przydatne w przypadku kolekcji
źródło
Inną interesującą częścią użycia znakowania tylko do odczytu może być ochrona pola przed inicjalizacją w singletonie.
na przykład w kodzie z csharpindepth :
readonly odgrywa niewielką rolę w ochronie pola Singleton przed dwukrotnym zainicjowaniem. Innym szczegółem jest to, że dla wspomnianego scenariusza nie można użyć const, ponieważ const wymusza tworzenie w czasie kompilacji, ale singleton tworzy w czasie wykonywania.
źródło
readonly
można zainicjować w deklaracji lub uzyskać jej wartość tylko od konstruktora. W przeciwieństwie doconst
tego musi być inicjowany i deklarowany jednocześnie.readonly
ma wszystko coconst
ma, plus inicjalizację konstruktorakod https://repl.it/HvRU/1
źródło