@donstack, faktycznie zgodnie z odniesieniem do C # , pole tylko do odczytu można przypisać i przypisać wiele razy w deklaracji pola i konstruktorze.
Marques
Odpowiedzi:
1289
Oprócz widocznej różnicy
konieczność zadeklarowania wartości w czasie definicji wartości constVS readonlymoże być obliczana dynamicznie, ale musi zostać przypisana przed wyjściem konstruktora. Po tym jest zamrożona.
'const' są niejawnie static. ClassName.ConstantNameAby uzyskać do nich dostęp, użyj notacji.
Jest subtelna różnica. Rozważ klasę zdefiniowaną w AssemblyA.
AssemblyBodwołuje się AssemblyAi używa tych wartości w kodzie. Po skompilowaniu
w przypadku constwartości jest to jak szukanie-zamiana, wartość 2 jest „wypalona” w AssemblyBIL. Oznacza to, że jeśli jutro zaktualizuję I_CONST_VALUEdo 20 w przyszłości. AssemblyBmiałbym jeszcze 2, dopóki go nie skompiluję .
w przypadku readonlywartości jest jak refw pamięci. Wartość nie jest wprowadzana do AssemblyBIL. Oznacza to, że jeśli lokalizacja pamięci zostanie zaktualizowana, AssemblyBotrzymuje nową wartość bez ponownej kompilacji. Jeśli więc I_RO_VALUEzaktualizowano do 30, wystarczy tylko zbudować AssemblyA. Nie trzeba ponownie kompilować wszystkich klientów.
Więc jeśli masz pewność, że wartość stałej się nie zmieni, użyj a const.
publicconstint CM_IN_A_METER =100;
Ale jeśli masz stałą, która może się zmienić (np. Precyzja zapisu) .. lub w razie wątpliwości użyj readonly.
publicreadonlyfloat PI =3.14;
Aktualizacja: Aku musi uzyskać wzmiankę, ponieważ najpierw zwrócił na to uwagę. Muszę też podłączyć tam, gdzie się tego nauczyłem ... Skuteczne C # - Bill Wagner
staticPunktem wydaje się być najważniejszym i użyteczny punkt -consts are implicitly static
LCJ
28
Najważniejsza jest część dotycząca wartości odniesienia. Stałe wartości można zoptymalizować.
CodingBarfield
22
readonlyzmienne można zmieniać poza konstruktorem (odbicie). Tylko kompilator próbuje ci przeszkodzić w modyfikowaniu var poza konstruktorem.
Bitterblue
12
readonlyZmienne @ mini-me nie mogą być zmieniane po zakończeniu działania konstruktora, nawet poprzez odbicie. Środowisko wykonawcze nie wymusza tego. Środowisko wykonawcze nie zdarza się również do egzekwowania, które nie zmieniają string.Emptysię "Hello, world!", ale nadal nie będzie twierdzić, że to sprawia, string.Emptymodyfikować lub że kod nie należy zakładać, że string.Emptyzawsze będzie ciągiem o zerowej długości.
Jest gotcha z stałymi! Jeśli odwołujesz się do stałej z innego zestawu, jej wartość zostanie skompilowana bezpośrednio w zestawie wywołującym. W ten sposób, gdy zaktualizujesz stałą w referencyjnym zestawie, nie zmieni się ona w zestawie wywołującym!
Podczas dekompilacji (Reflector, ILSpy, ...) do stałej NIGDY NIE DOTYCZY żaden, niezależnie od tego samego zestawu lub innego zestawu, więc nie można w ogóle analizować użycia stałej w skompilowanym kodzie.
springy76
159
Stałe
Stałe są domyślnie statyczne
Muszą mieć wartość w czasie kompilacji (możesz mieć np. 3.14 * 2, ale nie możesz wywoływać metod)
Może być zadeklarowany w ramach funkcji
Są kopiowane do każdego zestawu, który ich używa (każdy zestaw otrzymuje lokalną kopię wartości)
Może być stosowany w atrybutach
Pola instancji tylko do odczytu
Musi mieć ustawioną wartość, zanim konstruktor zakończy pracę
Są oceniane podczas tworzenia instancji
Statyczne pola tylko do odczytu
Są oceniane, gdy wykonanie kodu trafia na odwołanie do klasy (gdy tworzona jest nowa instancja lub wykonywana jest metoda statyczna)
Musi mieć oszacowaną wartość do czasu ukończenia konstruktora statycznego
Nie zaleca się umieszczania na nich ThreadStaticAttribute (konstruktory statyczne będą wykonywane tylko w jednym wątku i ustawią wartość dla tego wątku; wszystkie inne wątki będą miały tę wartość niezainicjowaną)
Aby dodać, ReadOnly tylko dla typów referencji powoduje, że referencja jest tylko do odczytu, a nie wartości. Na przykład:
publicclassConst_V_Readonly{publicconstint I_CONST_VALUE =2;publicreadonlychar[] I_RO_VALUE =newChar[]{'a','b','c'};publicUpdateReadonly(){
I_RO_VALUE[0]='V';//perfectly legal and will update the value
I_RO_VALUE =newchar[]{'V'};//will cause compiler error}}
Czy istnieje jakikolwiek inny typ odniesienia string, którego można użyć jako stałej?
springy76
Możesz mieć constz typami referencyjnymi innymi niż string, ale stała może mieć tylko wartość null.
Mike Rosoft
40
To wyjaśnia to . Podsumowanie: const musi być zainicjowany w czasie deklaracji, tylko do odczytu może zostać zainicjowany na konstruktorze (a zatem ma inną wartość w zależności od użytego konstruktora).
Jest mała gotcha z tylko do odczytu. Pole tylko do odczytu można ustawić wiele razy w konstruktorze (konstruktorach). Nawet jeśli wartość jest ustawiona w dwóch różnych konstruktorach łańcuchowych, jest nadal dozwolona.
publicclassSample{privatereadonlystring ro;publicSample(){
ro ="set";}publicSample(stringvalue):this(){
ro =value;// this works even though it was set in the no-arg ctor}}
Element stały jest definiowany w czasie kompilacji i nie można go zmienić w czasie wykonywania. Stałe są deklarowane jako pole za pomocą constsłowa kluczowego i muszą być inicjowane w trakcie deklaracji.
Członek readonlyjest jak stała, ponieważ reprezentuje niezmienną wartość. Różnica polega na tym, że element readonlyczłonkowski można zainicjować w środowisku wykonawczym, w konstruktorze, a także można go zainicjować w miarę ich deklarowania.
Nie mogą być statyczne , są statyczne. Powinieneś to wyjaśnić, jeśli miałeś na myśli, że nie można zadeklarowaćstatic const int i = 0;
nawfal
Czy możesz wyjaśnić, dlaczego constdeklaracje nie mogą być składane wewnątrz metod?
Minh Tran
21
Stała jest stałą czasu kompilacji, natomiast tylko do odczytu pozwala na obliczenie wartości w czasie wykonywania i ustawienie w konstruktorze lub inicjalizatorze pola. Zatem „stała” jest zawsze stała, ale „tylko do odczytu” jest przypisana tylko do odczytu.
Eric Lippert z zespołu C # ma więcej informacji na temat różnych rodzajów niezmienności
Oto kolejny link pokazujący, w jaki sposób const nie jest bezpieczny w wersji lub odpowiedni dla typów referencji.
Podsumowanie :
Wartość właściwości const jest ustawiana w czasie kompilacji i nie może się zmieniać w czasie wykonywania
Stała nie można oznaczyć jako statyczną - słowo kluczowe oznacza, że są statyczne, w przeciwieństwie do pól tylko do odczytu, które mogą.
Stała nie może być niczym innym niż typem wartości (prymitywnym)
Słowo kluczowe tylko do odczytu oznacza pole jako niezmienne. Jednak właściwość można zmienić wewnątrz konstruktora klasy
Słowo kluczowe tylko do odczytu można również połączyć ze statycznym, aby działało w ten sam sposób co const (przynajmniej na powierzchni). Istnieje znacząca różnica, gdy spojrzysz na IL między nimi
stałe pola są oznaczone jako „dosłowne” w IL, podczas gdy tylko do odczytu jest „początkowo”
Uważam, że constwartość jest taka sama dla wszystkich obiektów (i musi być inicjowana dosłownym wyrażeniem), podczas gdy readonlymoże być inna dla każdej instancji ...
Jeden z członków zespołu w naszym biurze udzielił następujących wskazówek, kiedy stosować const, static i readonly:
Używaj const, gdy masz zmienną typu, który możesz znać w czasie wykonywania (literał łańcuchowy, int, double, enum, ...), że chcesz, aby wszystkie wystąpienia lub konsumenci klasy mieli dostęp do miejsca, w którym wartość nie powinna się zmieniać.
Użyj statycznego, gdy masz dane, które mają umożliwić wszystkim instancjom lub konsumentom klasy dostęp do miejsca, w którym wartość może się zmienić.
Użyj statycznego tylko do odczytu, gdy masz zmienną typu, której nie możesz znać w czasie wykonywania (obiekty), i chcesz, aby wszystkie instancje lub konsumenci klasy mieli dostęp do miejsca, w którym wartość nie powinna się zmienić.
Używaj tylko do odczytu, gdy masz zmienną na poziomie instancji, którą znasz podczas tworzenia obiektu, która nie powinna się zmienić.
Ostatnia uwaga: stałe pole jest statyczne, ale odwrotność nie jest prawdziwa.
Myślę, że masz na myśli „rozmawiać”. Odwrotnością byłoby „pole niestałe nie jest statyczne”. Co może, ale nie musi być prawdą. Przeciwnie, „pole statyczne jest (zawsze) stałe” nie jest prawdziwe.
Michael Blackburn
5
Oba są stałe, ale stała jest dostępna również w czasie kompilacji. Oznacza to, że jednym aspektem różnicy jest to, że można używać zmiennych const jako danych wejściowych do konstruktorów atrybutów, ale nie zmiennych tylko do odczytu.
Przykład:
publicstaticclassText{publicconststringConstDescription="This can be used.";publicreadonlystaticstringReadonlyDescription="Cannot be used.";}publicclassFoo{[Description(Text.ConstDescription)]publicintBarThatBuilds{{get;set;}}[Description(Text.ReadOnlyDescription)]publicintBarThatDoesNotBuild{{get;set;}}}
Zmienne oznaczone jako const są niewiele więcej niż silnie wpisanymi makrami #define, w czasie kompilacji odniesienia do zmiennych const są zastępowane wbudowanymi wartościami literałowymi. W konsekwencji można w ten sposób wykorzystywać tylko niektóre wbudowane pierwotne typy wartości. Zmienne oznaczone jako tylko do odczytu można ustawić w konstruktorze w czasie wykonywania, a ich tylko do odczytu jest wymuszane również w czasie wykonywania. Jest to związane z niewielkimi kosztami wydajności, ale oznacza to, że można używać tylko do odczytu dowolnego typu (nawet typów referencyjnych).
Również stałe zmienne są z natury statyczne, podczas gdy zmienne tylko do odczytu mogą być specyficzne dla instancji, jeśli jest to pożądane.
Dodano, że consts są silnie wpisane #define makra. W przeciwnym razie możemy odstraszyć wszystkich ludzi C lub C ++. :-)
Jason Baker,
4
CONST
Słowo kluczowe const można zastosować do pól lub zmiennych lokalnych
Musimy przypisać stałe pole w momencie deklaracji
Brak przydzielonej pamięci Ponieważ wartość const jest osadzona w samym kodzie IL po kompilacji. To jest jak znaleźć wszystkie wystąpienia stałej zmiennej i zastąpić jej wartością. Zatem kod IL po kompilacji będzie miał zakodowane wartości zamiast zmiennych const
Stałe w C # są domyślnie statyczne.
Wartość jest stała dla wszystkich obiektów
Występuje problem z wersją biblioteki dll - oznacza to, że za każdym razem, gdy zmieniamy publiczną zmienną const lub właściwość (W rzeczywistości nie powinno się jej zmieniać teoretycznie), każdy inny dll lub zestaw, który używa tej zmiennej, musi zostać przebudowany
Tylko typy wbudowane w C # można zadeklarować jako stałe
Pole Const nie może być przekazane jako parametr ref lub out
Tylko czytać
Słowo kluczowe readonly dotyczy tylko pól, a nie zmiennych lokalnych
Możemy przypisać pole tylko do odczytu w momencie deklaracji lub w konstruktorze, a nie w innych metodach.
pamięć dynamiczna przydzielona do pól tylko do odczytu i możemy uzyskać wartość w czasie wykonywania.
Readonly należy do obiektu utworzonego w ten sposób, do którego dostęp jest możliwy tylko poprzez instancję klasy. Aby uczynić go członkiem klasy, musimy dodać statyczne słowo kluczowe przed tylko do odczytu.
Wartość może być różna w zależności od zastosowanego konstruktora (ponieważ należy do obiektu klasy)
Jeśli zadeklarujesz typy inne niż pierwotne (typ odwołania) jako tylko do odczytu, tylko odwołanie jest niezmienne, a nie obiekt, który zawiera.
Ponieważ wartość jest uzyskiwana w czasie wykonywania, nie ma problemu z wersją biblioteki DLL dla pól / właściwości tylko do odczytu.
Możemy przekazać pole tylko do odczytu jako parametry ref lub out w kontekście konstruktora.
Ponieważ const naprawdę działa tylko z podstawowymi typami danych, jeśli chcesz pracować z klasą, możesz czuć się „zmuszony” do korzystania z ReadOnly. Uważaj jednak na pułapkę! ReadOnly oznacza, że nie można zastąpić obiektu innym obiektem (nie można sprawić, aby odnosiło się do innego obiektu). Ale każdy proces, który ma odniesienie do obiektu, może dowolnie modyfikować wartości wewnątrz obiektu!
Nie daj się zatem pomylić, że ReadOnly sugeruje, że użytkownik nie może nic zmienić. W języku C # nie ma prostej składni, aby zapobiec zmianie instancji klasy przez jej wewnętrzne wartości (o ile mi wiadomo).
Tak, to bardziej ogólny temat. Jeśli masz właściwość get only ujawniającą listę arraylist, nadal możesz ją modyfikować. Nie można ustawić innej listy arraylist dla tej właściwości, ale nie można powstrzymać użytkownika przed zmianą listy arraylist.
Gishu,
3
A constmusi być zakodowane na stałe , gdzie readonlymożna ustawić w konstruktorze klasy.
Istnieje zauważalna różnica między polami const i readonly w C # .Net
const jest domyślnie statyczny i musi być inicjalizowany ze stałą wartością, której nie można później modyfikować. Zmiana wartości również nie jest dozwolona w konstruktorach. Nie można go używać ze wszystkimi typami danych. Dla ex-DateTime. Nie można go używać z typem danych DateTime.
tylko do odczytu można zadeklarować jako statyczne, ale nie konieczne. Nie ma potrzeby inicjowania w momencie deklaracji. Jego wartość można przypisać lub zmienić za pomocą konstruktora. Daje to przewagę, gdy jest używany jako element klasy instancji. Dwie różne instancje mogą mieć różną wartość pola tylko do odczytu. Na przykład -
class A
{publicreadonlyintId;public A(int i){Id= i;}}
Następnie pole tylko do odczytu można zainicjować za pomocą natychmiastowych wartości określonych w następujący sposób:
A objOne =new A(5);
A objTwo =new A(10);
Tutaj instancja objOne będzie miała wartość pola tylko do odczytu jako 5, a objTwo ma 10. To nie jest możliwe przy użyciu const.
Stała zostanie skompilowana do konsumenta jako wartość dosłowna, podczas gdy ciąg statyczny będzie służył jako odniesienie do zdefiniowanej wartości.
W ramach ćwiczenia spróbuj utworzyć bibliotekę zewnętrzną i zużyć ją w aplikacji konsolowej, a następnie zmienić wartości w bibliotece i ponownie skompilować (bez ponownej kompilacji programu konsumenckiego), upuścić bibliotekę DLL do katalogu i uruchomić plik EXE ręcznie, powinieneś znaleźć że ciąg stały się nie zmienia.
@Andrew Hare - tak, właśnie sprawdziłem. Jestem bardzo zaskoczony, to jest prawdziwa gotcha, jestem naprawdę bardzo zaskoczony, zdumiony, że tak jest ...!
ljs
Sprzeciwiam się jednak stosowaniu tutaj wskaźnika słowa. Nie jest to wskazówka, że to odniesienie, a tam jest różnica w C #, jak można manipulować niezarządzanymi wskaźniki w trybie niebezpiecznym, dlatego ważne jest, aby odróżnić dwa.
ljs
2
Stały
Musimy podać wartość do pola const, gdy jest zdefiniowane. Następnie kompilator zapisuje wartość stałej w metadanych zestawu. Oznacza to, że stałą można zdefiniować tylko dla typu pierwotnego, takiego jak boolean, char, bajt i tak dalej. Stałe są zawsze uważane za elementy statyczne, a nie elementy instancji.
Tylko czytać
Pola tylko do odczytu można rozwiązać tylko w czasie wykonywania. Oznacza to, że możemy zdefiniować wartość dla wartości za pomocą konstruktora dla typu, w którym pole jest zadeklarowane. Weryfikacja jest wykonywana przez kompilator, do którego pola tylko do odczytu nie są zapisywane żadną metodą inną niż konstruktor.
Głównie; możesz przypisać wartość do statycznego pola tylko do odczytu do wartości nie stałej w czasie wykonywania, podczas gdy stałej należy przypisać wartość stałą.
Const i readonly są podobne, ale nie są dokładnie takie same. Pole const jest stałą czasu kompilacji, co oznacza, że tę wartość można obliczyć w czasie kompilacji. Pole tylko do odczytu umożliwia dodatkowe scenariusze, w których część kodu musi zostać uruchomiona podczas budowy tego typu. Po zakończeniu budowy pola tylko do odczytu nie można zmienić.
Na przykład stałych członków można użyć do zdefiniowania członków takich jak:
ponieważ wartości takie jak 3.14 i 0 są stałymi czasów kompilacji. Rozważ jednak przypadek, w którym definiujesz typ i chcesz podać niektóre jego wcześniejsze wersje. Na przykład, możesz chcieć zdefiniować klasę Kolor i podać „stałe” dla typowych kolorów, takich jak Czarny, Biały itp. Nie można tego zrobić z elementami stałymi, ponieważ prawa strona nie jest stała czasu kompilacji. Można to zrobić za pomocą zwykłych elementów statycznych:
publicclassColor{publicstaticColorBlack=newColor(0,0,0);publicstaticColorWhite=newColor(255,255,255);publicstaticColorRed=newColor(255,0,0);publicstaticColorGreen=newColor(0,255,0);publicstaticColorBlue=newColor(0,0,255);privatebyte red, green, blue;publicColor(byte r,byte g,byte b){
red = r;
green = g;
blue = b;}}
ale nie ma nic, co powstrzymałoby klienta Color od zepsucia się nim, być może poprzez zamianę wartości czerni i bieli. Nie trzeba dodawać, że spowodowałoby to konsternację u innych klientów klasy Color. Funkcja „tylko do odczytu” rozwiązuje ten scenariusz. Po prostu wprowadzając słowo kluczowe tylko do odczytu w deklaracjach, zachowujemy elastyczną inicjalizację, jednocześnie zapobiegając pomijaniu kodu klienta.
publicclassColor{publicstaticreadonlyColorBlack=newColor(0,0,0);publicstaticreadonlyColorWhite=newColor(255,255,255);publicstaticreadonlyColorRed=newColor(255,0,0);publicstaticreadonlyColorGreen=newColor(0,255,0);publicstaticreadonlyColorBlue=newColor(0,0,255);privatebyte red, green, blue;publicColor(byte r,byte g,byte b){
red = r;
green = g;
blue = b;}}
Warto zauważyć, że stałe elementy są zawsze statyczne, podczas gdy element tylko do odczytu może być statyczny lub nie, tak jak zwykłe pole.
Możliwe jest użycie jednego słowa kluczowego do tych dwóch celów, ale prowadzi to do problemów z wersją lub problemów z wydajnością. Załóżmy przez chwilę, że użyliśmy do tego jednego słowa kluczowego (const), a programista napisał:
publicclass A
{publicstaticconst C =0;}
a inny programista napisał kod, który polegał na A:
publicclass B
{staticvoidMain(){Console.WriteLine(A.C);}}
Czy generowany kod może polegać na tym, że AC jest stałą czasową kompilacji? Czyli użycie AC można po prostu zastąpić wartością 0? Jeśli powiesz „tak”, oznacza to, że twórca A nie może zmienić sposobu inicjalizacji AC - wiąże to ręce twórcy A bez pozwolenia. Jeśli powiesz „nie” w tym pytaniu, ważna optymalizacja zostanie pominięta. Być może autor A jest przekonany, że AC zawsze będzie wynosić zero. Użycie zarówno const, jak i readonly pozwala twórcy A określić intencję. To zapewnia lepsze zachowanie wersjonowania, a także lepszą wydajność.
Różnica polega na tym, że wartość statycznego pola tylko do odczytu jest ustawiana w czasie wykonywania, więc może mieć inną wartość dla różnych wykonań programu. Jednak wartość stałego pola jest ustawiona na stałą czasową kompilacji.
Pamiętaj: W przypadku typów referencji, w obu przypadkach (statyczny i instancja), modyfikator tylko do odczytu uniemożliwia przypisanie nowego odwołania do pola. W szczególności nie czyni niezmiennego obiektu wskazywanym przez odniesienie.
Zmienne stałe są deklarowane i inicjowane w czasie kompilacji. Wartości nie można zmienić po totemach. Zmienne tylko do odczytu zostaną zainicjowane tylko ze statycznego konstruktora klasy. Tylko do odczytu jest używany tylko wtedy, gdy chcemy przypisać wartość w czasie wykonywania.
Twoja definicja „tylko do odczytu”, którą można zmienić, jest błędna. Myślę, że przez „zmianę” miałeś na myśli „set”, na przykład „można go ustawić w czasie wykonywania”.
Ahmed
0
Jedną rzecz do dodania do tego, co ludzie powiedzieli powyżej. Jeśli masz zestaw zawierający wartość tylko do odczytu (np. Readonly MaxFooCount = 4;), możesz zmienić wartość, którą wywołują zestawy, wysyłając nową wersję tego zestawu o innej wartości (np. Readonly MaxFooCount = 5;)
Ale w przypadku const będzie on składany w kodzie dzwoniącego podczas kompilacji dzwoniącego.
Jeśli osiągnąłeś ten poziom biegłości w C #, jesteś gotowy na książkę Billa Wagnera, Skuteczny C #: 50 konkretnych sposobów na poprawę twojego C #, który szczegółowo odpowiada na to pytanie (i 49 innych rzeczy).
Odpowiedzi:
Oprócz widocznej różnicy
const
VSreadonly
może być obliczana dynamicznie, ale musi zostać przypisana przed wyjściem konstruktora. Po tym jest zamrożona.static
.ClassName.ConstantName
Aby uzyskać do nich dostęp, użyj notacji.Jest subtelna różnica. Rozważ klasę zdefiniowaną w
AssemblyA
.AssemblyB
odwołuje sięAssemblyA
i używa tych wartości w kodzie. Po skompilowaniuconst
wartości jest to jak szukanie-zamiana, wartość 2 jest „wypalona” wAssemblyB
IL. Oznacza to, że jeśli jutro zaktualizujęI_CONST_VALUE
do 20 w przyszłości.AssemblyB
miałbym jeszcze 2, dopóki go nie skompiluję .readonly
wartości jest jakref
w pamięci. Wartość nie jest wprowadzana doAssemblyB
IL. Oznacza to, że jeśli lokalizacja pamięci zostanie zaktualizowana,AssemblyB
otrzymuje nową wartość bez ponownej kompilacji. Jeśli więcI_RO_VALUE
zaktualizowano do 30, wystarczy tylko zbudowaćAssemblyA
. Nie trzeba ponownie kompilować wszystkich klientów.Więc jeśli masz pewność, że wartość stałej się nie zmieni, użyj a
const
.Ale jeśli masz stałą, która może się zmienić (np. Precyzja zapisu) .. lub w razie wątpliwości użyj
readonly
.Aktualizacja: Aku musi uzyskać wzmiankę, ponieważ najpierw zwrócił na to uwagę. Muszę też podłączyć tam, gdzie się tego nauczyłem ... Skuteczne C # - Bill Wagner
źródło
static
Punktem wydaje się być najważniejszym i użyteczny punkt -consts are implicitly static
readonly
zmienne można zmieniać poza konstruktorem (odbicie). Tylko kompilator próbuje ci przeszkodzić w modyfikowaniu var poza konstruktorem.readonly
Zmienne @ mini-me nie mogą być zmieniane po zakończeniu działania konstruktora, nawet poprzez odbicie. Środowisko wykonawcze nie wymusza tego. Środowisko wykonawcze nie zdarza się również do egzekwowania, które nie zmieniająstring.Empty
się"Hello, world!"
, ale nadal nie będzie twierdzić, że to sprawia,string.Empty
modyfikować lub że kod nie należy zakładać, żestring.Empty
zawsze będzie ciągiem o zerowej długości.Jest gotcha z stałymi! Jeśli odwołujesz się do stałej z innego zestawu, jej wartość zostanie skompilowana bezpośrednio w zestawie wywołującym. W ten sposób, gdy zaktualizujesz stałą w referencyjnym zestawie, nie zmieni się ona w zestawie wywołującym!
źródło
Stałe
Pola instancji tylko do odczytu
Statyczne pola tylko do odczytu
źródło
Aby dodać, ReadOnly tylko dla typów referencji powoduje, że referencja jest tylko do odczytu, a nie wartości. Na przykład:
źródło
string
, którego można użyć jako stałej?const
z typami referencyjnymi innymi niż string, ale stała może mieć tylko wartośćnull
.To wyjaśnia to . Podsumowanie: const musi być zainicjowany w czasie deklaracji, tylko do odczytu może zostać zainicjowany na konstruktorze (a zatem ma inną wartość w zależności od użytego konstruktora).
EDYCJA: Zobacz wyżej Gchau dla subtelnej różnicy
źródło
const
: Nigdzie nie można tego zmienić.readonly
: Tę wartość można zmienić tylko w konstruktorze. Nie można go zmienić w normalnych funkcjach.źródło
Jest mała gotcha z tylko do odczytu. Pole tylko do odczytu można ustawić wiele razy w konstruktorze (konstruktorach). Nawet jeśli wartość jest ustawiona w dwóch różnych konstruktorach łańcuchowych, jest nadal dozwolona.
źródło
Element stały jest definiowany w czasie kompilacji i nie można go zmienić w czasie wykonywania. Stałe są deklarowane jako pole za pomocą
const
słowa kluczowego i muszą być inicjowane w trakcie deklaracji.Członek
readonly
jest jak stała, ponieważ reprezentuje niezmienną wartość. Różnica polega na tym, że elementreadonly
członkowski można zainicjować w środowisku wykonawczym, w konstruktorze, a także można go zainicjować w miarę ich deklarowania.const
static
(są domyślnie statyczne)tylko czytać
źródło
static const int i = 0;
const
deklaracje nie mogą być składane wewnątrz metod?Stała jest stałą czasu kompilacji, natomiast tylko do odczytu pozwala na obliczenie wartości w czasie wykonywania i ustawienie w konstruktorze lub inicjalizatorze pola. Zatem „stała” jest zawsze stała, ale „tylko do odczytu” jest przypisana tylko do odczytu.
Eric Lippert z zespołu C # ma więcej informacji na temat różnych rodzajów niezmienności
źródło
Oto kolejny link pokazujący, w jaki sposób const nie jest bezpieczny w wersji lub odpowiedni dla typów referencji.
Podsumowanie :
źródło
Tylko do odczytu : Wartość można zmienić za pomocą Ctor w czasie wykonywania. Ale nie poprzez funkcję członka
Stała : Defult static. Wartości nie można zmienić z dowolnego miejsca (Ctor, funkcja, środowisko uruchomieniowe itp. Nigdzie)
źródło
Jeszcze jedna gotcha: wartości tylko do odczytu można zmienić za pomocą „przebiegłego” kodu poprzez odbicie.
Czy mogę zmienić prywatne dziedziczone pole tylko do odczytu w języku C # za pomocą odbicia?
źródło
Uważam, że
const
wartość jest taka sama dla wszystkich obiektów (i musi być inicjowana dosłownym wyrażeniem), podczas gdyreadonly
może być inna dla każdej instancji ...źródło
Jeden z członków zespołu w naszym biurze udzielił następujących wskazówek, kiedy stosować const, static i readonly:
Ostatnia uwaga: stałe pole jest statyczne, ale odwrotność nie jest prawdziwa.
źródło
Oba są stałe, ale stała jest dostępna również w czasie kompilacji. Oznacza to, że jednym aspektem różnicy jest to, że można używać zmiennych const jako danych wejściowych do konstruktorów atrybutów, ale nie zmiennych tylko do odczytu.
Przykład:
źródło
kiedy stosować
const
lubreadonly
const
readonly
App.config
, ale gdy inicjuje on nie może być zmienionaźródło
Zmienne oznaczone jako const są niewiele więcej niż silnie wpisanymi makrami #define, w czasie kompilacji odniesienia do zmiennych const są zastępowane wbudowanymi wartościami literałowymi. W konsekwencji można w ten sposób wykorzystywać tylko niektóre wbudowane pierwotne typy wartości. Zmienne oznaczone jako tylko do odczytu można ustawić w konstruktorze w czasie wykonywania, a ich tylko do odczytu jest wymuszane również w czasie wykonywania. Jest to związane z niewielkimi kosztami wydajności, ale oznacza to, że można używać tylko do odczytu dowolnego typu (nawet typów referencyjnych).
Również stałe zmienne są z natury statyczne, podczas gdy zmienne tylko do odczytu mogą być specyficzne dla instancji, jeśli jest to pożądane.
źródło
CONST
Tylko czytać
źródło
Kolejna gotcha .
Ponieważ const naprawdę działa tylko z podstawowymi typami danych, jeśli chcesz pracować z klasą, możesz czuć się „zmuszony” do korzystania z ReadOnly. Uważaj jednak na pułapkę! ReadOnly oznacza, że nie można zastąpić obiektu innym obiektem (nie można sprawić, aby odnosiło się do innego obiektu). Ale każdy proces, który ma odniesienie do obiektu, może dowolnie modyfikować wartości wewnątrz obiektu!
Nie daj się zatem pomylić, że ReadOnly sugeruje, że użytkownik nie może nic zmienić. W języku C # nie ma prostej składni, aby zapobiec zmianie instancji klasy przez jej wewnętrzne wartości (o ile mi wiadomo).
źródło
A
const
musi być zakodowane na stałe , gdziereadonly
można ustawić w konstruktorze klasy.źródło
Istnieje zauważalna różnica między polami const i readonly w C # .Net
const jest domyślnie statyczny i musi być inicjalizowany ze stałą wartością, której nie można później modyfikować. Zmiana wartości również nie jest dozwolona w konstruktorach. Nie można go używać ze wszystkimi typami danych. Dla ex-DateTime. Nie można go używać z typem danych DateTime.
tylko do odczytu można zadeklarować jako statyczne, ale nie konieczne. Nie ma potrzeby inicjowania w momencie deklaracji. Jego wartość można przypisać lub zmienić za pomocą konstruktora. Daje to przewagę, gdy jest używany jako element klasy instancji. Dwie różne instancje mogą mieć różną wartość pola tylko do odczytu. Na przykład -
Następnie pole tylko do odczytu można zainicjować za pomocą natychmiastowych wartości określonych w następujący sposób:
Tutaj instancja objOne będzie miała wartość pola tylko do odczytu jako 5, a objTwo ma 10. To nie jest możliwe przy użyciu const.
źródło
Stała zostanie skompilowana do konsumenta jako wartość dosłowna, podczas gdy ciąg statyczny będzie służył jako odniesienie do zdefiniowanej wartości.
W ramach ćwiczenia spróbuj utworzyć bibliotekę zewnętrzną i zużyć ją w aplikacji konsolowej, a następnie zmienić wartości w bibliotece i ponownie skompilować (bez ponownej kompilacji programu konsumenckiego), upuścić bibliotekę DLL do katalogu i uruchomić plik EXE ręcznie, powinieneś znaleźć że ciąg stały się nie zmienia.
źródło
Stały
Musimy podać wartość do pola const, gdy jest zdefiniowane. Następnie kompilator zapisuje wartość stałej w metadanych zestawu. Oznacza to, że stałą można zdefiniować tylko dla typu pierwotnego, takiego jak boolean, char, bajt i tak dalej. Stałe są zawsze uważane za elementy statyczne, a nie elementy instancji.
Tylko czytać
Pola tylko do odczytu można rozwiązać tylko w czasie wykonywania. Oznacza to, że możemy zdefiniować wartość dla wartości za pomocą konstruktora dla typu, w którym pole jest zadeklarowane. Weryfikacja jest wykonywana przez kompilator, do którego pola tylko do odczytu nie są zapisywane żadną metodą inną niż konstruktor.
Więcej informacji na temat obu wyjaśniono tutaj w tym artykule
źródło
Głównie; możesz przypisać wartość do statycznego pola tylko do odczytu do wartości nie stałej w czasie wykonywania, podczas gdy stałej należy przypisać wartość stałą.
źródło
Const i readonly są podobne, ale nie są dokładnie takie same. Pole const jest stałą czasu kompilacji, co oznacza, że tę wartość można obliczyć w czasie kompilacji. Pole tylko do odczytu umożliwia dodatkowe scenariusze, w których część kodu musi zostać uruchomiona podczas budowy tego typu. Po zakończeniu budowy pola tylko do odczytu nie można zmienić.
Na przykład stałych członków można użyć do zdefiniowania członków takich jak:
ponieważ wartości takie jak 3.14 i 0 są stałymi czasów kompilacji. Rozważ jednak przypadek, w którym definiujesz typ i chcesz podać niektóre jego wcześniejsze wersje. Na przykład, możesz chcieć zdefiniować klasę Kolor i podać „stałe” dla typowych kolorów, takich jak Czarny, Biały itp. Nie można tego zrobić z elementami stałymi, ponieważ prawa strona nie jest stała czasu kompilacji. Można to zrobić za pomocą zwykłych elementów statycznych:
ale nie ma nic, co powstrzymałoby klienta Color od zepsucia się nim, być może poprzez zamianę wartości czerni i bieli. Nie trzeba dodawać, że spowodowałoby to konsternację u innych klientów klasy Color. Funkcja „tylko do odczytu” rozwiązuje ten scenariusz. Po prostu wprowadzając słowo kluczowe tylko do odczytu w deklaracjach, zachowujemy elastyczną inicjalizację, jednocześnie zapobiegając pomijaniu kodu klienta.
Warto zauważyć, że stałe elementy są zawsze statyczne, podczas gdy element tylko do odczytu może być statyczny lub nie, tak jak zwykłe pole.
Możliwe jest użycie jednego słowa kluczowego do tych dwóch celów, ale prowadzi to do problemów z wersją lub problemów z wydajnością. Załóżmy przez chwilę, że użyliśmy do tego jednego słowa kluczowego (const), a programista napisał:
a inny programista napisał kod, który polegał na A:
Czy generowany kod może polegać na tym, że AC jest stałą czasową kompilacji? Czyli użycie AC można po prostu zastąpić wartością 0? Jeśli powiesz „tak”, oznacza to, że twórca A nie może zmienić sposobu inicjalizacji AC - wiąże to ręce twórcy A bez pozwolenia. Jeśli powiesz „nie” w tym pytaniu, ważna optymalizacja zostanie pominięta. Być może autor A jest przekonany, że AC zawsze będzie wynosić zero. Użycie zarówno const, jak i readonly pozwala twórcy A określić intencję. To zapewnia lepsze zachowanie wersjonowania, a także lepszą wydajność.
źródło
Tylko do odczytu: Wartość zostanie zainicjowana tylko raz z konstruktora klasy.
const: można zainicjować w dowolnej funkcji, ale tylko raz
źródło
Różnica polega na tym, że wartość statycznego pola tylko do odczytu jest ustawiana w czasie wykonywania, więc może mieć inną wartość dla różnych wykonań programu. Jednak wartość stałego pola jest ustawiona na stałą czasową kompilacji.
Pamiętaj: W przypadku typów referencji, w obu przypadkach (statyczny i instancja), modyfikator tylko do odczytu uniemożliwia przypisanie nowego odwołania do pola. W szczególności nie czyni niezmiennego obiektu wskazywanym przez odniesienie.
Szczegółowe informacje można znaleźć w C # Często zadawane pytania na ten temat: http://blogs.msdn.com/csharpfaq/archive/2004/12/03/274791.aspx
źródło
Zmienne stałe są deklarowane i inicjowane w czasie kompilacji. Wartości nie można zmienić po totemach. Zmienne tylko do odczytu zostaną zainicjowane tylko ze statycznego konstruktora klasy. Tylko do odczytu jest używany tylko wtedy, gdy chcemy przypisać wartość w czasie wykonywania.
źródło
Const : Bezwzględna wartość stałą w czasie życia aplikacji.
Tylko do odczytu : Można to zmienić w czasie wykonywania.
źródło
Jedną rzecz do dodania do tego, co ludzie powiedzieli powyżej. Jeśli masz zestaw zawierający wartość tylko do odczytu (np. Readonly MaxFooCount = 4;), możesz zmienić wartość, którą wywołują zestawy, wysyłając nową wersję tego zestawu o innej wartości (np. Readonly MaxFooCount = 5;)
Ale w przypadku const będzie on składany w kodzie dzwoniącego podczas kompilacji dzwoniącego.
Jeśli osiągnąłeś ten poziom biegłości w C #, jesteś gotowy na książkę Billa Wagnera, Skuteczny C #: 50 konkretnych sposobów na poprawę twojego C #, który szczegółowo odpowiada na to pytanie (i 49 innych rzeczy).
źródło