const
e readonly
são semelhantes, mas não são exatamente iguais.
Um const
campo é uma constante em tempo de compilação, o que significa que esse valor pode ser calculado em tempo de compilação. Um readonly
campo permite cenários adicionais em que algum código deve ser executado durante a construção do tipo. Após a construção, umreadonly
campo não pode ser alterado.
Por exemplo, os const
membros podem ser usados para definir membros como:
struct Test
{
public const double Pi = 3.14;
public const int Zero = 0;
}
Como valores como 3,14 e 0 são constantes em tempo de compilação. No entanto, considere o caso em que você define um tipo e deseja fornecer algumas instâncias pré-fabricadas. Por exemplo, você pode definir uma classe Color e fornecer "constantes" para cores comuns, como preto, branco etc. Não é possível fazer isso com membros const, pois o lado direito não é uma constante em tempo de compilação. Pode-se fazer isso com membros estáticos regulares:
public class Color
{
public static Color Black = new Color(0, 0, 0);
public static Color White = new Color(255, 255, 255);
public static Color Red = new Color(255, 0, 0);
public static Color Green = new Color(0, 255, 0);
public static Color Blue = new Color(0, 0, 255);
private byte red, green, blue;
public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}
Porém, não há nada que impeça um cliente da Color de trocá-lo, talvez trocando os valores de preto e branco. Escusado será dizer que isso causaria consternação para outros clientes da classe Color. O recurso "somente leitura" aborda esse cenário.
Simplesmente introduzindo o readonly
palavra chave nas declarações, preservamos a inicialização flexível e impedimos que o código do cliente mexa.
public class Color
{
public static readonly Color Black = new Color(0, 0, 0);
public static readonly Color White = new Color(255, 255, 255);
public static readonly Color Red = new Color(255, 0, 0);
public static readonly Color Green = new Color(0, 255, 0);
public static readonly Color Blue = new Color(0, 0, 255);
private byte red, green, blue;
public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}
É interessante notar que os membros const são sempre estáticos, enquanto um membro somente leitura pode ser estático ou não, assim como um campo regular.
É possível usar uma única palavra-chave para esses dois propósitos, mas isso leva a problemas de versão ou de desempenho. Suponhamos por um momento que usamos uma única palavra-chave para isso (const) e um desenvolvedor escreveu:
public class A
{
public static const C = 0;
}
e um desenvolvedor diferente escreveu um código que contava com A:
public class B
{
static void Main() => Console.WriteLine(A.C);
}
Agora, o código gerado pode confiar no fato de que o AC é uma constante em tempo de compilação? Ou seja, o uso de AC pode simplesmente ser substituído pelo valor 0? Se você disser "sim" a isso, isso significa que o desenvolvedor de A não pode mudar a maneira como o CA é inicializado - isso amarra as mãos do desenvolvedor de A sem permissão.
Se você disser "não" a esta pergunta, uma otimização importante será perdida. Talvez o autor de A tenha certeza de que AC sempre será zero. O uso de const e readonly permite que o desenvolvedor de A especifique a intenção. Isso contribui para um melhor comportamento de versão e também um melhor desempenho.
static readonly
: tente usar uma const dentro de umaIEnumerator
que desencadeie uma irrecuperávelyield
e você obterá um temido "erro interno do compilador" . Não testei o código fora do Unity3D, mas confio que seja um bug mono ou .NET . É uma questão de c # , no entanto.