Por que String.Empty não é uma constante?


188

No .Net, por que String.Empty é somente leitura em vez de uma constante? Só estou imaginando se alguém sabe qual foi o raciocínio por trás dessa decisão.


5
Esta questão pode resolver este, a resposta breve é, ninguém sabe ...
gdoron está apoiando Monica

Sim, +1 pela resposta de Eric Lippert, obrigado!
travis

Dado especialmente que Decimal.Zero é const (a partir da perspectiva do usuário que é ...)
Hamish Grubijan

Respostas:


147

O motivo static readonlyusado em vez de constdeve-se ao uso com código não gerenciado, conforme indicado pela Microsoft aqui na versão Common Source Infrastructure 2.0 de versão compartilhada . O arquivo para analisar é sscli20\clr\src\bcl\system\string.cs.

A constante Vazia mantém o valor da sequência vazia. Precisamos chamar o construtor String para que o compilador não marque isso como literal.

Marcar isso como literal significaria que ele não aparece como um campo que podemos acessar do nativo.

Encontrei essas informações neste artigo útil no CodeProject .


Eu realmente aprecio se você pode explicar este comentário (porque Jon Skeet não poderia ...) ver aqui: stackoverflow.com/questions/8462697/...
gdoron está apoiando Monica

2
@ Gdoron: Meu palpite (e é um palpite) é este. Quando um valor é definido como literal (uma constante), seu valor é inserido nos locais onde é referenciado, enquanto que quando não é definido como literal, a fonte do valor é referenciada e o valor real é recuperado em tempo de execução. Suspeito que o último possa garantir que o empacotamento adequado da string ocorra entre nativo e .NET em tempo de execução - se fosse literal, talvez o compilador nativo precisasse de alguma forma puxar o valor literal para seu código nativo, o que provavelmente não é factível. Isso tudo é conjectura da minha parte, no entanto.
Jeff Yates

7
Isso significa que é necessário usar "", em vez de string.Empty para valores de parâmetro padrão nos métodos. O que é um pouco chato.
precisa

17
"" pode parecer um erro, enquanto uma string. Vazio mostra intenção deliberada
Christopher Stevenson

3
@JeffYates eu acrescentaria que o fato de não ser consistente já é irritante. As pessoas veriam o restante do código e se perguntariam "por que ele está usando" "aqui em vez de String.Empty?". Estou seriamente considerando não usar String.Emptymais apenas por esse motivo.
amigos estão dizendo sobre julealgon

24

Eu acho que há muita confusão e respostas ruins aqui.

Primeiro de tudo, os constcampos são staticmembros ( não membros da instância ).

Verifique a seção 10.4 Constantes da especificação da linguagem C #.

Mesmo que as constantes sejam consideradas membros estáticos, uma declaração constante não requer nem permite um modificador estático.

Se os public constmembros são estáticos, não se pode considerar que uma constante criará um novo objeto.

Diante disso, as seguintes linhas de código fazem exatamente a mesma coisa com relação à criação de um novo Objeto.

public static readonly string Empty = "";
public const string Empty = "";

Aqui está uma observação da Microsoft que explica a diferença entre os 2:

A palavra-chave readonly é diferente da palavra-chave const. Um campo const só pode ser inicializado na declaração do campo. Um campo somente leitura pode ser inicializado na declaração ou em um construtor. Portanto, os campos somente leitura podem ter valores diferentes, dependendo do construtor usado. Além disso, enquanto um campo const é uma constante em tempo de compilação, o campo somente leitura pode ser usado para constantes de tempo de execução, ...

Então, acho que a única resposta plausível aqui é a de Jeff Yates.


+1 para as palavras gentis e esclarecimentos sobre as especificações do C # somente leitura const e estática.
911 Jeff Yates

17
Relendo isso, discordo disso const stringe static readonly stringfaço a mesma coisa. Os valores const são substituídos no código vinculado, enquanto os valores estáticos somente leitura são referenciados. Se você tiver uma constbiblioteca A usada pela biblioteca B, a biblioteca B substituirá todas as referências a essa constvariável por seu valor literal; se essa variável fosse static readonlysubstituída, seria referenciada e seu valor determinado em tempo de execução.
Jeff Yates

3
O ponto de Jeff é importante ao fazer referência a bibliotecas. Se você recompilar A e redistribuí-lo, sem recompilar B , B ainda estará usando os valores antigos.
Mark Sowul

4
String.Empty read only instead of a constant?

Se você tornar qualquer string constante , o compilador será substituído pela string realmente todos os lugares que você chamar e você preencherá seu código com a mesma string todo e, quando o código for executado, também será necessário ler repetidamente essa string da memória diferente dados.

Se você deixar sua string de leitura apenas em um lugar, pois é a String.Empty , o programa manterá a mesma string apenas em um local e a lerá, ou fará referência a ela - mantendo os dados na memória mínimos.

Além disso, se você compilar qualquer dll usando o String.Empty como const e, por qualquer motivo, o String.Empty for alterado, a dll compilada não funcionará mais da mesma maneira, porque o cost cria o código interno para realmente manter uma cópia da string em todas as chamadas.

Veja este código por exemplo:

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;    
    }
}

virá pelo compilador como:

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;

    }
}

e a chamada de montagem

        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 

Editar: erro de digitação corrigido


Então, isso significa que a string const deve ser sempre instanciada com a classe que contém essa const? Parece que é muito melhor usar estática somente leitura então.
o furioso

@ theberserker também é melhor, mas você tem todas as opções para usar.
precisa

> então a dll compilada não funcionará mais da mesma forma, porque o custo cria o código interno para realmente manter uma cópia da string em todas as chamadas. @Aristos Isso não está certo. Depois que o código é compilado, a "cópia" da string será referenciada no bloco TEXT do executável, e todo o código fará referência apenas ao mesmo bloco de memória. O que você citou em seu segundo passo é simplesmente um passo intermediário.
Peter Dolkens

@ user1533523 obrigado pela nota - Vou fazer um teste quando eu encontrar algum tempo para verificar isso
Aristos

Como você conseguiu esse código de montagem? C # não compila para montagem!
jv110

0

Esta resposta existe para fins históricos.

Originalmente:

Porque Stringé uma classe e, portanto, não pode ser uma constante.

Discussão estendida:

Muitos diálogos úteis foram elaborados ao examinar esta resposta e, em vez de excluí-la, esse conteúdo é reproduzido diretamente:

No .NET, (ao contrário de Java), string e String são exatamente iguais. E sim, você pode ter constantes literais de cadeia de caracteres no .net - DrJokepu

Você está dizendo que uma classe não pode ter constantes? #: 226 StingyJack às 16:58

Sim, os objetos precisam usar somente leitura. Somente estruturas podem fazer constantes. Eu acho que quando você usa, em stringvez do Stringcompilador, muda a const para um somente leitura para você. Tudo relacionado a manter os programadores em C felizes. - Garry Shutler 03/02/09 às 16:59

tvanfosson apenas explicou um pouco mais detalhadamente. "X não pode ser uma constante, porque o Y que contém é uma classe" era um pouco livre de contexto demais;) #: 1128 Leonidas

string.Empty é uma propriedade estática que retorna uma instância da classe String, ou seja, a string vazia, não a própria classe de string. - tvanfosson 03/02/09 às 17:01

Vazio é uma instância somente leitura (não é uma propriedade) da classe String. #: 314 senfo às 17:02

Cabeça doendo. Ainda acho que estou certo, mas agora tenho menos certeza. Pesquisa necessária hoje à noite! Garry Shutler / Fev 3 '09 às 17:07

A cadeia vazia é uma instância da classe de cadeia. Vazio é um campo estático (não uma propriedade, estou corrigido) na classe String. Basicamente, a diferença entre um ponteiro e o que ele aponta. Se não fosse somente leitura, poderíamos mudar a qual instância o campo Vazio se refere. #: 23410 tvanfosson às 17:07

Garry, você não precisa fazer nenhuma pesquisa. Pense nisso. String é uma classe. Vazio é uma instância de uma String. #: 314 senfo às 17:12

Há algo que ainda não entendi: como diabos o construtor estático da classe String pode criar uma instância da classe String? Não é algum tipo de cenário de "galinha ou ovo"? #: 28411 DrJokepu 17:12 5

Esta resposta estaria correta para quase qualquer outra classe, exceto System.String. O .NET faz muito caso especial de desempenho para seqüências de caracteres, e uma delas é que você PODE ter constantes de seqüência de caracteres, apenas tente. Nesse caso, Jeff Yates tem a resposta correta. Joel Mueller Feb 3 '09 às 19:25

Conforme descrito em §7.18, uma expressão constante é uma expressão que pode ser totalmente avaliada em tempo de compilação. Como a única maneira de criar um valor não nulo de um tipo de referência que não seja string é aplicar o novo operador e, como o novo operador não é permitido em uma expressão constante, o único valor possível para constantes dos tipos de referência diferente de string é nulo. Os dois comentários anteriores foram retirados diretamente da especificação da linguagem C # e reiteram o que Joel Mueller mencionou. - senfo 04/02/09 às 15:05 5


Por favor, vote na resposta correta. Se você Goto Definition, verá que está na classe String e é uma instância de String. O fato de aparecer em minúsculas é uma mágica do compilador.
Garry Shutler

Não fui eu quem votou contra você, mas no .NET, (ao contrário de Java), string e String são exatamente iguais. E sim, você pode ter string literal constantes em .NET
Tamas Czinege

10
Esta resposta estaria correta para quase qualquer outra classe, exceto System.String. O .NET faz muito caso especial de desempenho para seqüências de caracteres, e uma delas é que você PODE ter constantes de seqüência de caracteres, apenas tente. Nesse caso, Jeff Yates tem a resposta correta.
Joel Mueller

7
Eu quase apaguei esta resposta, pois surgiu uma resposta muito melhor, mas vale a pena manter a discussão nesses comentários.
Garry Shutler 04/02/09

1
@ Garry, você tem sorte de ler seu último comentário, caso contrário eu também votaria. Uma string possui um recurso especial no .NET, que, mesmo que seja uma classe ref, pode ser uma const.
Shimmy Weitzhandler,
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.