A const pública é ruim?

Imagem de capa A const pública é ruim?

A const pública é ruim?

Declarar um número ou string como const pública é considerado uma prática ruim? Vamos dar uma olhada no que uma variável const significa em primeiro lugar.

Vamos pegar a definição da referência oficial do C#:

"Você usa a palavra-chave const para declarar um campo constante ou uma constante local. Campos constantes e locais não são variáveis e não podem ser modificados. Constantes podem ser números, valores booleanos, strings ou uma referência nula. Não crie uma constante para representar informações que você espera mudar a qualquer momento."

Agora para começar esta parte é importante "Campos constantes e locais não são variáveis ...". Isso é essencial. Vamos dar uma olhada no seguinte trecho de código:

using System;

Console.Write(MyClass.MyConstantString);

public  class  MyClass

{ 

    public  const  string MyConstantString = "Hello";

}

O compilador reduzirá esse termo para o seguinte código Fonte em sharplab.io

internal  class  Program
{

     private  static  void <Main>$(string[] args)
     { 
         Console.Write("Hello");
     }
}
public  class  MyClass
{ 
     public  const  string MyConstantString = "Hello";
}

Hupps. Onde está a referência a MyClass.MyConstantString no Console.Write? Exatamente não existindo mais. campos const e locais de fato não são variáveis e, portanto, serão "substituídos" pelo compilador em tempo de compilação em todos os lugares em que a constante for usada. Isso pode trazer um grande problema:

Assemblies de referência

Imagine que você tem a seguinte classe no Assembly A:

public  class  MyClassInAssemblyA
{
     public  const  string MyConstantString = "Hello";
}

E um usuário da classe no Assembly B:

public  class  MyClassInAssemblyA
{ 
    public void WriteSomething() => Console.WriteLine(MyClassInAssemblyA.MyConstantString);
}

Se compilarmos isso e chamarmos WriteSomething, o console imprimirá "Hello". Agora vamos mais longe e mudamos MyConstantString de "Olá" para "mundo". Nós reimplantamos o Assembly A, mas não o Assembly B, qual será a saída de WriteSomething? Ainda "Olá". Por quê? Porque, como mostrado anteriormente, a string const é codificada no assembly. Isso significa que para refletir as alterações mais recentes, você também precisa recompilar o Assembly B. Agora, isso não é muito útil quando você desenvolve software onde tudo está sob seu controle, mas pode ser complicado, por exemplo, se você desenvolver plugins, onde o chamador não ser recompilado automaticamente.

Como consertar isso

A correção mais fácil é usar um campo estático somente leitura. Então, tomando nosso exemplo desde o início, refatoramos isso para um campo estático somente leitura:

using System;

Console.Write(MyClass.MyConstantString);

public  class  MyClass
{
    public  static  readonly  string  MyConstantString = "Hello";
}

E o código resultante ficará assim:

internal  class  Program
{ 
    private  static  void <Main>$(string[] args)
    {
        Console.Write(MyClass.MyConstantString);
     } 
} 
public  class  MyClass
{ 
    public  static  readonly  string MyConstantString = "Hello"; 
}

Podemos ver claramente que o Console.Write agora usa a referência "real" em vez da string codificada. Ou seja, se alterarmos MyClass.MyConstantString, ele também será refletido automaticamente.

?? A mudança de const pública para readonly estática pública é considerada uma alteração importante. Você perde a compatibilidade binária, de origem e de reflexão. Então, se você fizer versionamento semântico, terá que aumentar o número principal. Esteja ciente disso.

Além disso, você não pode usar campos/variáveis estáticos somente leitura nos seguintes cenários:

  • Argumentos de atributo
  • Alternar declarações
  • Declarações de parâmetros opcionais

A const pública é ruim então?

Como sempre: Depende. Principalmente no fato de você ter controle total sobre todo o fluxo e código-fonte, se você provavelmente não tiver. Além disso, se você está 100% certo de que seu const nunca mudará, vá em frente. Algo como public const int Zero = 0 ou Pi. Caso contrário, seja muito cauteloso se você quiser usar const público. O mesmo se aplica para const protegido. Tudo o que é visível fora da sua montagem.

É claro que const privado ou const interno são seguros a esse respeito.