Jaka jest różnica między const
i readonly
w C #?
Kiedy używałbyś jednego nad drugim?
Jaka jest różnica między const
i readonly
w C #?
Kiedy używałbyś jednego nad drugim?
Odpowiedzi:
Oprócz widocznej różnicy
const
VS readonly
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
.
public class Const_V_Readonly
{
public const int I_CONST_VALUE = 2;
public readonly int I_RO_VALUE;
public Const_V_Readonly()
{
I_RO_VALUE = 3;
}
}
AssemblyB
odwołuje się AssemblyA
i używa tych wartości w kodzie. Po skompilowaniu
const
wartości jest to jak szukanie-zamiana, wartość 2 jest „wypalona” w AssemblyB
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 jak ref
w pamięci. Wartość nie jest wprowadzana do AssemblyB
IL. Oznacza to, że jeśli lokalizacja pamięci zostanie zaktualizowana, AssemblyB
otrzymuje nową wartość bez ponownej kompilacji. Jeśli więc I_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
.
public const int 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
.
public readonly float 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
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ć, że string.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!
Aby dodać, ReadOnly tylko dla typów referencji powoduje, że referencja jest tylko do odczytu, a nie wartości. Na przykład:
public class Const_V_Readonly
{
public const int I_CONST_VALUE = 2;
public readonly char[] I_RO_VALUE = new Char[]{'a', 'b', 'c'};
public UpdateReadonly()
{
I_RO_VALUE[0] = 'V'; //perfectly legal and will update the value
I_RO_VALUE = new char[]{'V'}; //will cause compiler error
}
}
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
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.
public class Sample {
private readonly string ro;
public Sample() {
ro = "set";
}
public Sample(string value) : 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ą const
słowa kluczowego i muszą być inicjowane w trakcie deklaracji.
public class MyClass
{
public const double PI1 = 3.14159;
}
Członek readonly
jest jak stała, ponieważ reprezentuje niezmienną wartość. Różnica polega na tym, że element readonly
członkowski można zainicjować w środowisku wykonawczym, w konstruktorze, a także można go zainicjować w miarę ich deklarowania.
public class MyClass1
{
public readonly double PI2 = 3.14159;
//or
public readonly double PI3;
public MyClass2()
{
PI3 = 3.14159;
}
}
const
static
(są domyślnie statyczne)tylko czytać
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
Oto kolejny link pokazujący, w jaki sposób const nie jest bezpieczny w wersji lub odpowiedni dla typów referencji.
Podsumowanie :
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)
Jeszcze jedna gotcha: wartości tylko do odczytu można zmienić za pomocą „przebiegłego” kodu poprzez odbicie.
var fi = this.GetType()
.BaseType
.GetField("_someField",
BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(this, 1);
Czy mogę zmienić prywatne dziedziczone pole tylko do odczytu w języku C # za pomocą odbicia?
Uważam, że const
wartość jest taka sama dla wszystkich obiektów (i musi być inicjowana dosłownym wyrażeniem), podczas gdy readonly
moż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:
Ostatnia uwaga: stałe pole jest statyczne, ale odwrotność nie jest prawdziwa.
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:
public static class Text {
public const string ConstDescription = "This can be used.";
public readonly static string ReadonlyDescription = "Cannot be used.";
}
public class Foo
{
[Description(Text.ConstDescription)]
public int BarThatBuilds {
{ get; set; }
}
[Description(Text.ReadOnlyDescription)]
public int BarThatDoesNotBuild {
{ get; set; }
}
}
kiedy stosować const
lubreadonly
const
readonly
App.config
, ale gdy inicjuje on nie może być zmienionaZmienne 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.
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).
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.
public const DateTime dt = DateTime.Today; //throws compilation error
public const string Name = string.Empty; //throws compilation error
public readonly string Name = string.Empty; //No error, legal
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
{
public readonly int Id;
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.
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
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:
struct Test
{
public const double Pi = 3.14;
public const int Zero = 0;
}
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:
public class Color
{
public static Color Black = new Color(0, 0, 0);
public static Color White = new Color(255, 255, 255);
public static Color Red = new Color(255, 0, 0);
public static Color Green = new Color(0, 255, 0);
public static Color Blue = new Color(0, 0, 255);
private byte red, green, blue;
public Color(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.
public class Color
{
public static readonly Color Black = new Color(0, 0, 0);
public static readonly Color White = new Color(255, 255, 255);
public static readonly Color Red = new Color(255, 0, 0);
public static readonly Color Green = new Color(0, 255, 0);
public static readonly Color Blue = new Color(0, 0, 255);
private byte red, green, blue;
public Color(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ł:
public class A
{
public static const C = 0;
}
a inny programista napisał kod, który polegał na A:
public class B
{
static void Main() {
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.
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
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.
Const : Bezwzględna wartość stałą w czasie życia aplikacji.
Tylko do odczytu : Można to zmienić w czasie wykonywania.
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).