Nie można użyć String.Empty jako wartości domyślnej dla opcjonalnego parametru

89

Czytam Efektywny C # autorstwa Billa Wagnera. W punkcie 14 - Minimize Duplicate Initialization Logic , przedstawia on następujący przykład użycia nowej funkcji parametrów opcjonalnych w konstruktorze:

public MyClass(int initialCount = 0, string name = "")

Zauważ, że użył ""zamiast string.Empty.
On komentuje:

Zauważysz [w powyższym przykładzie], że drugi konstruktor określił „” jako domyślną wartość parametru name , a nie bardziej zwyczajową string.Empty. Dzieje się tak, ponieważ string.Emptynie jest to stała czasu kompilacji. Jest to statyczna właściwość zdefiniowana w klasie string. Ponieważ nie jest to stała kompilacji, nie można jej użyć jako wartości domyślnej parametru.

Jeśli nie możemy użyć string.Emptystatyki we wszystkich sytuacjach, czy nie jest to sprzeczne z jej celem? Pomyślałem, że użyjemy go, aby upewnić się, że mamy niezależny od systemu sposób odwoływania się do pustego łańcucha. Czy moje zrozumienie jest złe? Dzięki.

UPDATE
Tylko komentarz uzupełniający. Według MSDN:

Każdy opcjonalny parametr ma wartość domyślną jako część swojej definicji. Jeśli dla tego parametru nie zostanie przesłany żaden argument, używana jest wartość domyślna. Wartości domyślne muszą być stałymi.

W takim przypadku nie będziemy mogli System.Environment.NewLineani używać ani używać nowo utworzonych obiektów jako wartości domyślnych. Nie korzystałem jeszcze z VS2010 i to jest rozczarowujące!

Mikeyg36
źródło
2
Nie znam żadnych różnic między sposobem reprezentacji pustych ciągów na różnych platformach. To nie jest nowa linia.
Tom Cabanski
Tak, myślałem o tym, więc czy po prostu wygląda to ładniej w kodzie?
Mikeyg36
1
CLR, a nie „System”, jest czynnikiem decydującym o tym, czy „” jest pustym łańcuchem, czy nie. Myślę więc, że można spokojnie założyć, że „” jest niezależnym od systemu sposobem odwoływania się do ciągu znaków w zgodnej implementacji CLR.
Chris Taylor,
„niezależne od systemu”? eee, w przeciwieństwie do „” specyficznego dla systemu? (???)
Qwertie
Zgodnie z MSDN: wartością tego pola jest łańcuch o zerowej długości, „”. więc to oczywiście nie ma nic wspólnego z niezależnością platformy, na co wskazuje wiele osób. Jednak nadal wydaje się, że ludzie tak naprawdę nie wiedzą, dlaczego należy go używać!
Mikeyg36

Odpowiedzi:

66

Podobnie jak w przypadku kompilatora C # 2.0, i tak nie ma to większego sensu String.Empty, aw rzeczywistości w wielu przypadkach jest to pesymizacja, ponieważ kompilator może wstawić niektóre odniesienia do, ""ale nie może zrobić tego samego z String.Empty.

W C # 1.1 warto było unikać tworzenia wielu niezależnych obiektów zawierających pusty ciąg, ale te czasy już minęły. ""działa dobrze.

Andy Mortimer
źródło
7
Nawet w .NET 1.1 nie utworzyłoby wielu niezależnych obiektów. Nie pamiętam szczegółów różnic między 1.1 a 2.0 pod tym względem, ale to nie jest tak, że dosłowne internowanie stringów zostało wprowadzone dopiero w 2.0.
Jon Skeet
Dziękuję za wyjaśnienie. Rozejrzałem się i nie znalazłem dobrego podsumowania zmian w C # 2.0, chociaż jestem pewien, że czytałem wcześniej. Znalazłem odpowiedź StackOverflow z 2008 roku z kilkoma linkami do bardziej technicznych informacji. stackoverflow.com/questions/151472/…
Andy Mortimer
1
Skinę głową, chociaż nie lubię mówić, że string nie ma sensu. Pusty, ponieważ używam go dość intensywnie. Uważam, że wygląda po prostu czyściej, chociaż to moja osobista opinia. Istnieje wiele miejsc string.Empty nie może być użyty, a nie mam żadnego problemu przy użyciu „” w tych przypadkach
xximjasonxx
15
Zauważyłem, że znacznie łatwiej jest szybko zidentyfikować pusty ciąg za pomocą String.Empty niż dwa razy spojrzeć na „”, aby upewnić się, że nie ma w nim apostrofu lub czegoś podobnego. +1 za wyjaśnienie.
NotMe
11
+1 Chris. Również w VS naprawdę nie możesz wyszukiwać użycia „” (poza standardowym wyszukiwaniem, które również przywróci wszystkie pasujące teksty, w tym komentarze i znaczniki). Możesz wyszukać zastosowania specyficzne dla kodu za pomocą string.Empty.
MutantNinjaCodeMonkey
53

Nic nie stoi na przeszkodzie, aby zdefiniować własną stałą dla pustego ciągu, jeśli naprawdę chcesz go użyć jako opcjonalnej wartości parametru:

const string String_Empty = "";

public static void PrintString(string s = String_Empty)
{
    Console.WriteLine(s);
}

[Tak na marginesie, jednym z powodów wolą String.Emptynad ""w ogóle, które nie zostały wymienione w innych odpowiedzi, jest to, że istnieją różne znaki Unicode (zero-width stolarzy, etc.), które są skutecznie niewidoczne gołym okiem. Więc coś, co wygląda, ""niekoniecznie jest pustym ciągiem, podczas gdy String.Emptywiesz dokładnie, czego używasz. Rozumiem, że to nie jest częste źródło błędów, ale jest to możliwe.]

Matthew Strawbridge
źródło
2
Istnieją również niewidoczne znaki identyfikacyjne, więc coś, co wygląda jak String_Empty, niekoniecznie. Standard Unicode ma w dużej mierze ignorowany rozdział dotyczący względów bezpieczeństwa.
Jim Balter
25

Z pierwotnego pytania:

Pomyślałem, że użyjemy go, aby upewnić się, że mamy niezależny od systemu sposób odwoływania się do pustego ciągu.

W jaki sposób pusty ciąg może różnić się w zależności od systemu? To zawsze ciąg bez znaków! Byłbym naprawdę przerażony, gdybym kiedykolwiek znalazł implementację, która string.Empty == ""zwróciłaby fałsz :) To nie to samo, co coś podobnego Environment.NewLine.

Z postu o zleceniach antyterrorystycznych:

Chcę String.Empty może być używany jako parametr domyślny w następnej wersji C #. :RE

Cóż, to z pewnością się nie wydarzy.

Chociaż osobiście wolałbym również bardzo inny mechanizm domyślny, sposób działania parametrów opcjonalnych był w .NET od samego początku - i zawsze oznacza to osadzenie stałej w metadanych, tak aby kod wywołujący mógł skopiować tę stałą do wywołania witryna, jeśli nie zostanie podany odpowiedni argument.

Ze string.Emptyto naprawdę bezcelowe - używając ""będą robić to, co chcesz; czy używanie dosłownego ciągu znaków jest takie bolesne? (Wszędzie używam dosłownego - nigdy nie używam string.Empty- ale to inny argument).

Właśnie to mnie zaskakuje w tym pytaniu - skarga obraca się wokół czegoś, co tak naprawdę nie powoduje prawdziwego problemu. Jest to ważniejsze w przypadkach, gdy chcesz, aby wartość domyślna była obliczana w czasie wykonywania, ponieważ w rzeczywistości może się różnić. Na przykład, mógłbym sobie wyobrazić przypadki, w których chciałbyś móc wywołać metodę z DateTimeparametrem i ustawić ją jako domyślną na „aktualny czas”. W tej chwili jedyne mało eleganckie obejście tego problemu, jakie znam, to:

public void RecordTime(string message, DateTime? dateTime = null)
{
    var realDateTime = dateTime ?? DateTime.UtcNow;
}

... ale to nie zawsze jest właściwe.

Podsumowując:

  • Bardzo wątpię, czy to kiedykolwiek będzie częścią C #
  • Bo i string.Emptytak jest to bezcelowe
  • W przypadku innych wartości, które naprawdę nie zawsze mają tę samą wartość, może to być naprawdę uciążliwe
Jon Skeet
źródło
To właściwie dobry sposób na rozwiązanie problemu. Tej samej rzeczy można użyć do przenoszenia / ustawiania innych zmiennych zależnych od urządzenia, takich jak Environment.Newline... Jedyne, czego brakuje w twoim przykładzie, to sprawdzenie zmiennej pod kątem wartości null i zwrócenie wyjątku z powrotem do programisty, mówiąc mu, że chociaż dopuszcza wartość null, to nie zaakceptowany. if(dateTime == null){ throw new ArgumentException("The dateTime parameter must be set. Nullable type used for device independent variable set.");}czy coś takiego. Ale naprawdę to lubię! Masz inne zastrzeżenia, aby zrobić to po swojemu?
MaxOvrdrv
@MaxOvrdrv: Nie chcesz, aby wartość null była błędem - chodzi o to, że gdy jest null, obliczasz wartość domyślną. Zastrzeżenie polega na tym, że nie pozwala na przekazywanie wartości null jako prawidłowej wartości samej w sobie.
Jon Skeet,
Masz co do tego całkowitą rację. Mój błąd. - I tak, to byłoby jedyne prawdziwe zastrzeżenie, prawda… nie jest tak źle. Ponownie: bardzo podoba mi się to rozwiązanie! :) Dzięki za wysłanie! :)
MaxOvrdrv
7

Nigdy nie używam stringów, puste, nie widzę w tym sensu. Może jest to łatwiejsze dla ludzi, którzy są naprawdę nowicjuszami w programowaniu, ale wątpię, by było to przydatne nawet do tego.

Hans Olsson
źródło
2
Może to zapobiega myleniu ""i " ", ale nie mogę powiedzieć, że " "to wszystko jest takie powszechne.
Greg
8
Proponuję każdemu, kto nie potrafi odróżnić tych potrzeb, albo lepszych okularów, albo obniżenia rozdzielczości ekranu. Mam zły wzrok i nie przypominam sobie, żeby kiedykolwiek popełniłem ten błąd (i muszę pracować z dużą ilością kodu, który zawiera oba te elementy).
Hans Olsson
2
string.Empty jest przydatne do ustalenia dokładnego zamiaru programisty. "" nic nie mówi o zamiarze, a co by było, gdyby intencją programisty było zainicjowanie zmiennej takiej jak ten "lol", ale zapomniał ... w tym przypadku jest nieskończona liczba możliwości i napis, przydaje się Empty i wykonuje lepszą robotę
przydatne
4

Myślę, że ideą string.Empty jest to, że poprawia czytelność. To nie jest jak nowa linia, w której istnieje różnica między tym, jak jest reprezentowana na różnych platformach. Szkoda, że ​​nie można go użyć w parametrze domyślnym. Jednak nie spowoduje to żadnych problemów, jeśli połączysz system Windows z czymś takim jak Mono w systemie Linux.

Tom Cabanski
źródło
5
Myślę, że prawdopodobnie masz rację, że chodzi o to, że niektórzy ludzie uważają je za String.Emptybardziej czytelne. . . osobiście jednak uważam, że to trochę zwariowane. ""jest prawdopodobnie najpowszechniejszym ciągiem, jaki istnieje i każdy widział go miliard razy, więc jak jest nieczytelny? String.Emptyjest tak samo przydatne, jakby istniał plik Int32.Zero.
Tim Goodman
3

Jako FYI wygląda na to, że to samo ograniczenie jest nakładane na wartości przekazywane do konstruktorów atrybutów - muszą one być stałe. Ponieważ string.empty jest zdefiniowany jako:

public static readonly string Empty

raczej niż rzeczywista stała, nie może być używana.

Shawn Eavis
źródło
2

Używam string.Emptywyłącznie dla czytelności.

Jeśli ktoś inny będzie musiał później przeczytać / zmienić mój kod, wie, że zamierzałem sprawdzić lub ustawić coś na pusty ciąg. Używanie po prostu ""może czasami powodować błędy i zamieszanie, ponieważ mogłem po prostu zapomnieć o umieszczeniu tam ciągu, który chciałem.

Na przykład:

if(someString == string.Empty)
{

}

vs

if(someString == "")
{

}

Pierwsze ifstwierdzenie wydaje mi się o wiele bardziej przemyślane i czytelne. Ponieważ jest to jednak tylko preferencja, naprawdę nie widzę rozbijania pociągu w konieczności używania ""zamiast string.Empty.

lukejkw
źródło
-2

Być może najlepszym rozwiązaniem tego problemu jest przeciążenie tej metody w ten sposób:

public static void PrintString() 
{ 
    PrintString(string.Empty);
}
lokum09
źródło
3
Jak to odpowiada na powyższe pytanie?
Pranav Singh
1
W jaki sposób pomaga przy domyślnych wartościach parametrów opcjonalnych?
domyślny język