Não é possível usar String.Empty como valor padrão para um parâmetro opcional

89

Estou lendo Effective C # de Bill Wagner. No Item 14 - Minimize Duplicate Initialization Logic , ele mostra o seguinte exemplo de uso do novo recurso de parâmetros opcionais em um construtor:

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

Observe que ele usou em ""vez de string.Empty.
Ele comenta:

Você notará [em um exemplo acima] que o segundo construtor especificou "" como o valor padrão no parâmetro de nome , em vez do mais usual string.Empty. Isso porque string.Emptynão é uma constante de tempo de compilação. É uma propriedade estática definida na classe string. Como não é uma constante de compilação, você não pode usá-la como o valor padrão de um parâmetro.

Se não podemos usar a string.Emptyestática em todas as situações, isso não anula o propósito dela? Pensei em usá-lo para ter certeza de que temos um meio independente do sistema de se referir à string vazia. Meu entendimento está errado? Obrigado.

ATUALIZAÇÃO
Apenas um comentário de acompanhamento. De acordo com o MSDN:

Cada parâmetro opcional possui um valor padrão como parte de sua definição. Se nenhum argumento for enviado para esse parâmetro, o valor padrão será usado. Os valores padrão devem ser constantes.

Então não podemos usar System.Environment.NewLinenenhum dos dois, ou usar objetos recém-instanciados como valores padrão. Eu não usei o VS2010 ainda, e isso é decepcionante!

Mikeyg36
fonte
2
Não estou ciente de quaisquer diferenças entre como as strings vazias são representadas em diferentes plataformas. Não é como uma nova linha.
Tom Cabanski
Certo, eu estava pensando nisso, então é que fica melhor no código?
Mikeyg36
1
O CLR e não o 'Sistema' é o fator determinante para saber se "" é uma string vazia ou não. Portanto, acho que você pode assumir com segurança que "" é uma maneira independente do sistema de se referir a uma string em uma implementação CLR compatível.
Chris Taylor
"independente do sistema"? er, ao contrário do "" específico do sistema? (???)
Qwertie
De acordo com o MSDN: O valor deste campo é a string de comprimento zero, "". então obviamente não tem nada a ver com independência de plataforma, como muitas pessoas estão apontando. Mesmo assim, parece que as pessoas realmente não sabem por que ele deve ser usado!
Mikeyg36

Respostas:

65

A partir do compilador C # 2.0, há muito pouco sentido para String.Emptyqualquer coisa e, na verdade, em muitos casos é uma pessimização, já que o compilador pode embutir algumas referências a, ""mas não pode fazer o mesmo com String.Empty.

No C # 1.1, era útil evitar a criação de muitos objetos independentes, todos contendo a string vazia, mas esses dias acabaram. ""funciona muito bem.

Andy Mortimer
fonte
7
Mesmo no .NET 1.1, ele não criaria "muitos" objetos independentes. Não consigo me lembrar dos detalhes das diferenças entre 1.1 e 2.0 a esse respeito, mas não é como se o internamento de literal de string só tivesse sido introduzido no 2.0.
Jon Skeet
Obrigado pelo esclarecimento. Dei uma olhada e não encontrei um bom resumo das mudanças no C # 2.0, embora tenha certeza de já ter lido um anteriormente. Eu encontrei uma resposta StackOverflow de 2008 com alguns links para mais informações técnicas. stackoverflow.com/questions/151472/…
Andy Mortimer
1
Vou concordar, embora eu não goste de dizer que não faz muito sentido usar string. Vazio, pois eu o uso muito. Acho que parece mais limpo, embora essa seja minha opinião pessoal. Há muitos lugares onde a string. Vazio não pode ser usado, e não tenho nenhum problema em usar "" nesses casos
xximjasonxx
14
Descobri que é muito mais fácil identificar rapidamente uma string vazia com String.Empty do que olhar duas vezes para "" para garantir que ela não tenha um apóstrofo ou algo parecido oculto nela. 1 para a explicação embora.
NotMe de
11
+1 Chris. Também no VS, você realmente não pode fazer uma pesquisa nos usos de "" (além de fazer o Find padrão que também irá trazer de volta todas as correspondências de texto, incluindo comentários e marcações). Você pode fazer uma pesquisa sobre usos específicos de código com string.Empty.
MutantNinjaCodeMonkey
53

Não há nada que o impeça de definir sua própria constante para a string vazia se você realmente quiser usá-la como um valor de parâmetro opcional:

const string String_Empty = "";

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

[Como um aparte, um motivo para preferir String.Emptysobre "", em geral, que não tenha sido mencionado em outras respostas, é que existem vários caracteres Unicode (marceneiro de largura zero, etc.) que são eficazmente invisível a olho nu. Portanto, algo que parece ""não é necessariamente a string vazia, enquanto com String.Emptyvocê sabe exatamente o que está usando. Reconheço que esta não é uma fonte comum de bugs, mas é possível.]

Matthew Strawbridge
fonte
2
Existem também caracteres identificadores invisíveis, então algo que se parece com String_Empty não é necessariamente. O padrão Unicode tem um capítulo amplamente ignorado sobre considerações de segurança.
Jim Balter
25

Da pergunta original:

Pensei em usá-lo para ter certeza de que temos um meio independente do sistema de se referir à string vazia.

De que forma a string vazia pode variar de sistema para sistema? É sempre uma string sem caracteres! Eu ficaria muito assustado se encontrasse uma implementação onde string.Empty == ""retornasse falso :) Isso não é o mesmo que algo parecido Environment.NewLine.

Da postagem de recompensa do Counter Terrorist:

Eu quero String.Empty pode ser usado como um parâmetro padrão na próxima versão C #. : D

Bem, isso certamente não vai acontecer.

Embora eu pessoalmente também tivesse gostado de um mecanismo de padronização muito diferente, a forma como os parâmetros opcionais funcionam tem sido no .NET desde o início - e isso sempre significa incorporar uma constante nos metadados, de modo que o código de chamada possa copiar essa constante na chamada site se nenhum argumento correspondente for fornecido.

Com string.Emptyele é realmente inútil - usar ""fará o que você quiser; é tão doloroso usar o literal de string? (Eu uso o literal em todos os lugares - nunca uso string.Empty- mas esse é um argumento diferente.)

Isso é o que me surpreende nesta questão - a reclamação gira em torno de algo que não causa um problema real. É mais importante nos casos em que você deseja que o padrão seja calculado no tempo de execução porque ele pode realmente variar. Por exemplo, eu poderia imaginar casos em que você deseja chamar um método com um DateTimeparâmetro e defini-lo como "a hora atual" como padrão. No momento, a única solução vagamente elegante que conheço para isso é:

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

... mas isso nem sempre é apropriado.

Em conclusão:

  • Duvido muito que isso algum dia faça parte do C #
  • Pois string.Emptyé inútil de qualquer maneira
  • Para outros valores que nem sempre têm o mesmo valor, pode ser realmente uma dor
Jon Skeet
fonte
Na verdade, essa é uma boa maneira de resolver o problema. A mesma coisa pode ser usada para transportar / definir outras variáveis ​​dependentes do dispositivo como Environment.Newline.. A única coisa que falta em seu exemplo seria uma verificação na variável para nulo e lançar uma exceção de volta para o desenvolvedor dizendo a ele que, embora seja anulável, é Não aceito. if(dateTime == null){ throw new ArgumentException("The dateTime parameter must be set. Nullable type used for device independent variable set.");}ou algo assim. Mas eu realmente gosto disso! Alguma outra advertência para fazer do seu jeito?
MaxOvrdrv
@MaxOvrdrv: Você não quer que seja nulo seja um erro - o ponto principal é que quando for nulo, você calcula um padrão. A ressalva é que ele não permite que null seja transmitido como um valor válido em si mesmo.
Jon Skeet de
Você está completamente certo sobre isso. Foi mal. - E sim, essa seria a única advertência real, não seria ... isso não é tão ruim. Novamente: eu realmente gosto dessa solução! :) Obrigado por postar! :)
MaxOvrdrv
7

Nunca uso string. Vazio, não consigo ver o sentido disso. Talvez facilite para as pessoas que são realmente novas em programação, mas duvido que seja útil até para isso.

Hans Olsson
fonte
2
Talvez evite confundir ""e " ", mas não posso dizer que " "seja tão comum.
Greg
8
Eu sugiro que qualquer pessoa que não saiba a diferença entre essas necessidades de óculos melhores ou diminuir a resolução de sua tela. Eu tenho problemas de visão e não me lembro de ter cometido esse erro (e tenho que trabalhar com muitos códigos que contêm os dois).
Hans Olsson
2
string.Empty é útil para descobrir a intenção exata do programador. "" não diz nada sobre a intenção, e se a intenção do programador fosse inicializar a variável como este "lol" mas esquecesse ... neste caso existem infinitas possibilidades e string, Empty vem útil e faz um trabalho melhor
helpfulBee
4

Acho que a ideia por trás do string.Empty é que aumenta a legibilidade. Não é como uma nova linha, onde há qualquer diferença entre como ela é representada em diferentes plataformas. É uma pena que não pode ser usado em um parâmetro padrão. No entanto, isso não causará problemas se você migrar entre o Windows e algo como Mono no Linux.

Tom Cabanski
fonte
5
Acho que você provavelmente está certo quanto ao ponto é que algumas pessoas consideram String.Emptymais legível. . . pessoalmente, porém, acho que é um pouco maluco. ""é provavelmente a string mais comum que existe e todo mundo já a viu um bilhão de vezes, então como é ilegível? String.Emptyé tão útil quanto se houvesse um Int32.Zero.
Tim Goodman
3

Como um FYI, parece que a mesma restrição é imposta aos valores passados ​​para os construtores de atributos - eles devem ser constantes. Uma vez que string.empty é definido como:

public static readonly string Empty

em vez de uma constante real, ela não pode ser usada.

Shawn Eavis
fonte
1

Eu uso string.Emptypuramente para facilitar a leitura.

Se outra pessoa precisar ler / alterar meu código mais tarde, eles sabem que eu pretendia verificar ou definir algo como uma string vazia. Usar apenas ""às vezes pode causar bugs e confusão, porque posso simplesmente ter esquecido de colocar a string que queria lá.

Por exemplo:

if(someString == string.Empty)
{

}

vs

if(someString == "")
{

}

A primeira ifdeclaração parece muito mais deliberada e legível para mim. Como isso é apenas uma preferência, eu realmente não vejo problema em ter que usar em ""vez de string.Empty.

lukejkw
fonte
-2

Talvez a melhor solução para este problema seja uma sobrecarga deste método, desta forma:

public static void PrintString() 
{ 
    PrintString(string.Empty);
}
lokum09
fonte
3
Como isso responde à pergunta acima?
Pranav Singh
1
Como isso ajuda com valores padrão para parâmetros opcionais?
localidade padrão