Dlaczego nieruchomość została string foo = string.Emptyuwzględniona w BCL? Wydaje się bardziej gadatliwy i nie jest bardziej przejrzysty niż użycie pustego ciągu ( string foo = "")
Nitpick: To nie jest część języka. Jest częścią BCL. VB.NET i F # mogą z niego korzystać, podobnie jak każdy inny język .NET.
Oded
19
Bo inaczej nie można robić złych rzeczy, takich jak typeof(string).GetField("Empty").SetValue(null, " ");;)
Mason Wheeler,
1
@MasonWheeler - Radość refleksji. Dla prawdziwego zła potrzebujesz introspekcji, co?
Oded
1
@MasonWheeler, +1. O Boże, gogle, nic nie robią!]
Machado,
1
@MasonWheeler To czyste, destylowane zło. Uwielbiam to. Pytanie, jeśli jesteś zainteresowany: czy nie byłoby bezpieczniej (i przyzwoicie) napisać to jako public static string Empty { get { return string.Intern(""); } }?
Jesse C. Slicer
Odpowiedzi:
55
Mogę tylko założyć tutaj:
string.Emptyzostało zdefiniowane dla jawności - podczas inicjowania łańcucha może nie być jasne z kontekstu, który ""rzeczywiście był wyraźnie oznaczony jako inicjator (zamiast nulllub powiedz " "lub po prostu jako miejsce na miejsce podczas testowania). Używanie string.Emptyjest zdecydowaną odpowiedzią na tego rodzaju zagadkę.
Może to być także powrót do C - pusty ciąg w C nie jest pustym ciągiem. Jest to tablica znaków, której pierwszy znak jest pusty (stąd pusty), co nie jest tym samym co C #. Chodzi mi o to, że w różnych językach reprezentowałbyś pusty ciąg znaków na różne sposoby (i mogą mieć różne znaczenia) - string.Emptywykluczając taką dwuznaczność.
W przeciwieństwie do tego, co inni mówią o wielu obiektach - nie stanowi to problemu, ponieważ dosłowne ciągi znaków zostaną internalizowane podczas kompilacji. Obejmuje to wartość string.Empty- "". Za każdym razem, gdy jedno z nich zostanie powtórzone w kodzie, obiekt zostanie pobrany z puli wewnętrznej. Dotyczy to domeny aplikacji .
+1 za bycie jedyną poprawną odpowiedzią do tej pory.
psr
Niektóre języki mogą nawet nie mieć literału pustego ciągu. Najwyraźniej standardowy Pascal nie.
dan04
2
„pusty ciąg w C nie jest pustym ciągiem” - ale mimo to, piszesz "", otrzymujesz {'\0'}, więc nie byłoby różnicy między pustym dosłownym ciągiem znaków a innym okrągłym sposobem jego zdefiniowania.
detly
14
Nie jestem w 100% pewien źródeł, z których się tego nauczyłem, ale niektóre z jego zalet obejmują:
Każdy ciąg w zestawie .NET jest unikalny, więc posiadanie
string foo ="";string bar ="";
daje 2 ciągi w zestawie wyjściowym, ponieważ ciągi są niezmienne. Posiadanie obu odniesień string.Emptyzmniejsza rozmiar zespołu.
Dosadność. Kiedy natrafisz na string.Emptyzamiar, jasne jest, że ma to być pusty ciąg. Ale jeśli natkniesz się na foo = ""to, czy programista usunął zawartość ciągu podczas testowania i zapomniał dodać go z powrotem, czy też tak powinno być?
Zachowanie w pamięci dwóch identycznych ciągów wydawałoby się dziwnym zachowaniem. Czy to w rzeczywistości jest zrobione?
Przypon
36
W rzeczywistości dzieje się coś przeciwnego - nazywa się to internowaniem ciągów (a dokładniej internowaniem literałów). Wiem na pewno, że odbywa się to w Javie i Pythonie, i jestem prawie pewien, że dzieje się tak również w językach .NET. Oczywiście może się to zdarzyć tylko w zakresie jednej jednostki tłumaczeniowej, więc jeśli dynamiczny moduł ładujący nie ujednolici takich danych, możesz skończyć z jednym pustym ciągiem na plik programu. Nadal niewiele.
9
@delnan ma absolutną rację. ""/ string.Emptysą internowane i zostanie utworzony tylko jeden obiekt.
Oded
11
@Andy - wszystkie literały łańcuchowe są internowane w .NET. Nie wszystkie łańcuchy. Programowo utworzone ciągi znaków nie są domyślnie internowane. Zobacz String.Intern w MSDN.
Oded
3
@Oded et alia: Właściwie nikt z was nie ma racji. Po pierwsze, literały są internowane w zespole, ale niekoniecznie między zespołami . Po drugie, to, czy pusty ciąg jest internowany w zestawach, jest szczegółem implementacji; niektóre wersje CLR robią, a niektóre nie. W jednej z odpowiedzi znajduje się link do mojego artykułu na ten temat; zobacz szczegóły.
Eric Lippert,
2
Nie zostanie utworzony żaden obiekt string.Empty. Użycie ""spowoduje utworzenie obiektu, który najprawdopodobniej będzie pochodził z wewnętrznej puli ciągów.
W przeszłości ludzie przeprowadzali testy i String.Emptywychodziły nieco szybciej, ale jest to mikrooptymalizacja.
String. Puste jest to:
//The Empty constant holds the empty string value. //We need to call the String constructor so that the compiler doesn't mark //this as a literal. //Marking this as a literal would mean that it doesn't show up as a field //which we can access from native. publicstaticreadonlyStringEmpty="";
Chodzi o String. Puste jest w zasadzie stałą dla „”. Znajdź autora String.cs dla głębszego znaczenia. :)
Jon Raynor
0
Jest to kwestia optymalizacji zużycia pamięci i optymalizacji porównywania ciągów. Za każdym razem, gdy używasz pustego ciągu w swojej aplikacji, alokujesz obiekt ciągu zawierający 0 znaków. Jeśli chodzi o porównywanie ciągów, można to zrobić, porównując odwołania (wskaźniki) zamiast znak po znaku, co jest szybsze nawet w przypadku pustych ciągów.
Jeśli używasz wielokrotnie tego samego ciągu w swojej aplikacji, możesz użyć tego samego mechanizmu, wywołując String.Intern () ze swoim ciągiem. Ale jeśli używasz każdego ciągu tylko raz, użyjesz tylko więcej pamięci.
Zatem String.Empty jest tylko specjalną optymalizacją przypadków, którą warto wykonać dla większości aplikacji .Net, dlatego została zintegrowana z BCL.
Łącza tylko odpowiedzi nie dają dobrych odpowiedzi. Jeśli Eric kiedykolwiek zreorganizuje swojego bloga, ta odpowiedź stanie się bezużyteczna. Proszę podsumować ten post tutaj więc mamy wszelkie informacje pod ręką.
ChrisF
7
@ChrisF: Nigdy nie mogę zreorganizować bloga. To byłaby przełomowa zmiana i wiesz, co ja o tym sądzę.
Eric Lippert,
1
@EricLippert - Zdaję sobie sprawę, że nigdy byś tego nie zrobił, jednak odpowiedzi tylko w linkach nie są dobrymi odpowiedziami i musimy zachęcać ludzi do tego.
ChrisF
3
@EricLippert Nie chodzi tylko o ulotne linki. Chodzi również o grzeczność dla czytelników, w odpowiedzi powinna znajdować się przynajmniej wystarczająca ilość treści, aby czytelnicy mogli wyrazić opinię, czy skorzystać z linku. Odpowiedź powinna mieć sens nawet w offline wersji SE.
typeof(string).GetField("Empty").SetValue(null, " ");
;)public static string Empty { get { return string.Intern(""); } }
?Odpowiedzi:
Mogę tylko założyć tutaj:
string.Empty
zostało zdefiniowane dla jawności - podczas inicjowania łańcucha może nie być jasne z kontekstu, który""
rzeczywiście był wyraźnie oznaczony jako inicjator (zamiastnull
lub powiedz" "
lub po prostu jako miejsce na miejsce podczas testowania). Używaniestring.Empty
jest zdecydowaną odpowiedzią na tego rodzaju zagadkę.Może to być także powrót do C - pusty ciąg w C nie jest pustym ciągiem. Jest to tablica znaków, której pierwszy znak jest pusty (stąd pusty), co nie jest tym samym co C #. Chodzi mi o to, że w różnych językach reprezentowałbyś pusty ciąg znaków na różne sposoby (i mogą mieć różne znaczenia) -
string.Empty
wykluczając taką dwuznaczność.W przeciwieństwie do tego, co inni mówią o wielu obiektach - nie stanowi to problemu, ponieważ dosłowne ciągi znaków zostaną internalizowane podczas kompilacji. Obejmuje to wartość
string.Empty
-""
. Za każdym razem, gdy jedno z nich zostanie powtórzone w kodzie, obiekt zostanie pobrany z puli wewnętrznej. Dotyczy to domeny aplikacji .źródło
""
, otrzymujesz{'\0'}
, więc nie byłoby różnicy między pustym dosłownym ciągiem znaków a innym okrągłym sposobem jego zdefiniowania.Nie jestem w 100% pewien źródeł, z których się tego nauczyłem, ale niektóre z jego zalet obejmują:
Każdy ciąg w zestawie .NET jest unikalny, więc posiadanie
daje 2 ciągi w zestawie wyjściowym, ponieważ ciągi są niezmienne. Posiadanie obu odniesień
string.Empty
zmniejsza rozmiar zespołu.string.Empty
zamiar, jasne jest, że ma to być pusty ciąg. Ale jeśli natkniesz się nafoo = ""
to, czy programista usunął zawartość ciągu podczas testowania i zapomniał dodać go z powrotem, czy też tak powinno być?źródło
""
/string.Empty
są internowane i zostanie utworzony tylko jeden obiekt.Nie zostanie utworzony żaden obiekt
string.Empty
. Użycie""
spowoduje utworzenie obiektu, który najprawdopodobniej będzie pochodził z wewnętrznej puli ciągów.W przeszłości ludzie przeprowadzali testy i
String.Empty
wychodziły nieco szybciej, ale jest to mikrooptymalizacja.String. Puste jest to:
źródło
Jest to kwestia optymalizacji zużycia pamięci i optymalizacji porównywania ciągów. Za każdym razem, gdy używasz pustego ciągu w swojej aplikacji, alokujesz obiekt ciągu zawierający 0 znaków. Jeśli chodzi o porównywanie ciągów, można to zrobić, porównując odwołania (wskaźniki) zamiast znak po znaku, co jest szybsze nawet w przypadku pustych ciągów.
Jeśli używasz wielokrotnie tego samego ciągu w swojej aplikacji, możesz użyć tego samego mechanizmu, wywołując String.Intern () ze swoim ciągiem. Ale jeśli używasz każdego ciągu tylko raz, użyjesz tylko więcej pamięci.
Zatem String.Empty jest tylko specjalną optymalizacją przypadków, którą warto wykonać dla większości aplikacji .Net, dlatego została zintegrowana z BCL.
Aby uzyskać więcej informacji na ten temat, zdecydowanie polecam przeczytanie posta na blogu Erica Lipperta .
Powinieneś także zapoznać się z dokumentacją, do której odwołuje się jego post na blogu.
źródło