W .Net dlaczego String.Empty jest tylko do odczytu zamiast stałej? Zastanawiam się tylko, czy ktoś wie, jakie było uzasadnienie tej decyzji.
W .Net dlaczego String.Empty jest tylko do odczytu zamiast stałej? Zastanawiam się tylko, czy ktoś wie, jakie było uzasadnienie tej decyzji.
Odpowiedzi:
Powodem static readonly
użycia zamiast tego const
jest użycie niezarządzanego kodu, jak wskazał Microsoft tutaj w wersji Shared Source Common Language Infrastructure 2.0 . Plik do obejrzenia to sscli20\clr\src\bcl\system\string.cs
.
Stała pusta przechowuje wartość pustego ciągu. Musimy wywołać konstruktor String, aby kompilator nie oznaczył tego jako literału.
Oznaczenie tego jako literału oznaczałoby, że nie pojawia się jako pole, do którego możemy uzyskać dostęp z natywnego.
Znalazłem te informacje z tego przydatnego artykułu w CodeProject .
String.Empty
już tylko z tego powodu.
Myślę, że jest tu wiele zamieszania i złych odpowiedzi.
Przede wszystkim const
pola są static
członkami ( nie członkami instancji ).
Sprawdź rozdział 10.4 Stałe specyfikacji języka C #.
Mimo że stałe są uważane za elementy statyczne, deklaracja stała nie wymaga ani nie pozwala na modyfikator statyczny.
Jeśli public const
członkowie są statyczni, nie można uznać, że stała utworzy nowy Obiekt.
Biorąc to pod uwagę, poniższe wiersze kodu robią dokładnie to samo w odniesieniu do tworzenia nowego obiektu.
public static readonly string Empty = "";
public const string Empty = "";
Oto uwaga od Microsoft, która wyjaśnia różnicę między 2:
Słowo kluczowe tylko do odczytu różni się od słowa kluczowego const. Pole const można zainicjować tylko w deklaracji pola. Pole tylko do odczytu można zainicjować w deklaracji lub w konstruktorze. Dlatego pola tylko do odczytu mogą mieć różne wartości w zależności od zastosowanego konstruktora. Ponadto, chociaż pole const jest stałą czasu kompilacji, pole tylko do odczytu może być użyte do stałych środowiska wykonawczego, ...
Uważam więc, że jedyną możliwą odpowiedzią jest odpowiedź Jeffa Yatesa.
const string
i static readonly string
robię to samo. Wartości stałych są podstawiane w połączonym kodzie, podczas gdy do statycznych wartości tylko do odczytu odwoływane są. Jeśli masz const
bibliotekę A, która jest używana przez bibliotekę B, biblioteka B zastąpi wszystkie odwołania do tej const
zmiennej jej wartością dosłowną; gdyby static readonly
zamiast niej zmienna ta byłaby przywołana, a jej wartość ustalona w czasie wykonywania.
String.Empty read only instead of a constant?
Jeśli uczynisz ciąg ciągiem stałym , kompilator zostanie zastąpiony ciągiem rzeczywistym wszędzie tam, gdzie go wywołasz, i wypełnisz kod tym samym ciągiem znaków po całym, a gdy kod zostanie uruchomiony, musisz również odczytywać ten ciąg znaków z innej pamięci dane.
Jeśli pozostawisz ciąg odczytywany tylko w jednym miejscu, tak jak to jest String.Empty
, program utrzyma ten sam ciąg tylko w jednym miejscu i odczyta go lub odniesie się do niego - utrzymując dane w pamięci minimum.
Również jeśli skompilujesz dowolną bibliotekę DLL przy użyciu String.Empty jako const, i z jakiegokolwiek powodu zmieni się String.Empty, wówczas skompilowana biblioteka dll nie będzie działać tak samo, ponieważ cost
sprawi, że wewnętrzny kod faktycznie zachowa kopię łańcucha przy każdym połączeniu.
Zobacz ten kod na przykład:
public class OneName
{
const string cConst = "constant string";
static string cStatic = "static string";
readonly string cReadOnly = "read only string";
protected void Fun()
{
string cAddThemAll ;
cAddThemAll = cConst;
cAddThemAll = cStatic ;
cAddThemAll = cReadOnly;
}
}
przyjdzie przez kompilator jako:
public class OneName
{
// note that the const exist also here !
private const string cConst = "constant string";
private readonly string cReadOnly;
private static string cStatic;
static OneName()
{
cStatic = "static string";
}
public OneName()
{
this.cReadOnly = "read only string";
}
protected void Fun()
{
string cAddThemAll ;
// look here, will replace the const string everywhere is finds it.
cAddThemAll = "constant string";
cAddThemAll = cStatic;
// but the read only will only get it from "one place".
cAddThemAll = this.cReadOnly;
}
}
i wezwanie do zgromadzenia
cAddThemAll = cConst;
0000003e mov eax,dword ptr ds:[09379C0Ch]
00000044 mov dword ptr [ebp-44h],eax
cAddThemAll = cStatic ;
00000047 mov eax,dword ptr ds:[094E8C44h]
0000004c mov dword ptr [ebp-44h],eax
cAddThemAll = cReadOnly;
0000004f mov eax,dword ptr [ebp-3Ch]
00000052 mov eax,dword ptr [eax+0000017Ch]
00000058 mov dword ptr [ebp-44h],eax
Edycja: poprawiona literówka
Ta odpowiedź istnieje dla celów historycznych.
Pierwotnie:
Ponieważ String
jest klasą i dlatego nie może być stałą.
Rozszerzona dyskusja:
Podczas weryfikacji tej odpowiedzi opracowano wiele przydatnych okien dialogowych, a zamiast jej usuwać, treść jest odtwarzana bezpośrednio:
W .NET, (w przeciwieństwie do Java) ciąg i Ciąg są dokładnie takie same. I tak, możesz mieć stałe literału ciągów w .NET - DrJokepu 3 lutego 09 o 16:57
Czy mówisz, że klasa nie może mieć stałych? - StingyJack 3 lutego 09 o 16:58
Tak, obiekty muszą używać tylko do odczytu. Tylko struktury mogą wykonywać stałe. Myślę, że kiedy użyjesz
string
zamiastString
kompilatora, zmieni const w readonly dla ciebie. Wszystko po to, by zadowolić programistów C. - Garry Shutler 3 lutego 09 o 16:59tvanfosson właśnie wyjaśnił to trochę bardziej gadatliwie. „X nie może być stały, ponieważ zawierająca Y jest klasą” była po prostu zbyt bezkontekstowa;) - Leonidas 3 lutego 09 '17:01
string.Empty jest właściwością statyczną, która zwraca instancję klasy String, a mianowicie pusty ciąg, a nie samą klasę string. - tvanfosson 3 lutego 09 o 17:01
Empty jest instancją tylko do odczytu (nie jest własnością) klasy String. - senfo 3 lutego 09 o 17:02
Ból głowy Nadal uważam, że mam rację, ale teraz jestem mniej pewny. Badania wymagane dziś wieczorem! - Garry Shutler 3 lutego 09 o 17:07
Pusty ciąg jest instancją klasy ciągu. Puste jest polem statycznym (nie właściwością, stoję poprawionym) w klasie String. Zasadniczo różnica między wskaźnikiem a rzeczą, na którą wskazuje. Gdyby nie było tylko do odczytu, moglibyśmy zmienić, do której instancji odnosi się pole Puste. - tvanfosson 3 lutego 09 o 17:07
Garry, nie musisz przeprowadzać żadnych badań. Pomyśl o tym. Łańcuch jest klasą. Puste jest wystąpieniem ciągu. - senfo 3 lutego 09 o 17:12
Jest coś, czego nie do końca rozumiem: jak, u licha, statyczny konstruktor klasy String może utworzyć instancję klasy String? Czy to nie jest scenariusz „kurczaka lub jajka”? - DrJokepu 3 lutego 09 o 17:12 5
Ta odpowiedź byłaby poprawna dla prawie każdej innej klasy oprócz System.String. .NET ma dużo specjalnej obudowy dla ciągów, a jedną z nich jest to, że MOŻESZ mieć stałe ciągów, po prostu spróbuj. W tym przypadku Jeff Yates ma poprawną odpowiedź. - Joel Mueller 3 lutego 09 o 19:25
Jak opisano w §7.18, wyrażenie stałe jest wyrażeniem, które można w pełni ocenić podczas kompilacji. Ponieważ jedynym sposobem utworzenia wartości innej niż null typu referencyjnego innego niż ciąg znaków jest zastosowanie nowego operatora, a ponieważ nowy operator nie jest dozwolony w wyrażeniu stałym, jedyna możliwa wartość dla stałych typów referencyjnych inny niż string jest pusty. Poprzednie dwa komentarze zostały zaczerpnięte bezpośrednio ze specyfikacji języka C # i powtórzą to, o czym wspomniał Joel Mueller. - senfo 4 lutego 09 o 15:05 5