Pregunta

Cuál es la diferencia entre const y readonly ¿Y usas uno sobre el otro?

¿Fue útil?

Solución

Aparte de la aparente diferencia de

  • tener que declarar el valor en el momento de una definición de un const contra readonly Los valores se pueden calcular dinámicamente pero deben asignarse antes de que salga el constructor.después de eso se congela.
  • 'las constantes son implícitas static.tu usas un ClassName.ConstantName notación para acceder a ellos.

Hay una diferencia sutil.Considere una clase definida en AssemblyA.

public class Const_V_Readonly
{
  public const int I_CONST_VALUE = 2;
  public readonly int I_RO_VALUE;
  public Const_V_Readonly()
  {
     I_RO_VALUE = 3;
  }
}

AssemblyB referencias AssemblyA y utiliza estos valores en el código.Cuando esto se compila,

  • en el caso de la const valor, es como buscar y reemplazar, el valor 2 está "integrado" en el AssemblyBEs IL.Esto significa que si mañana actualizo I_CONST_VALUE a 20 en el futuro. AssemblyB todavía tendría 2 hasta que lo recompile.
  • en el caso de la readonly valor, es como un ref a una ubicación de memoria.El valor no está incluido AssemblyBEs IL.Esto significa que si se actualiza la ubicación de la memoria, AssemblyB obtiene el nuevo valor sin recompilación.Así que si I_RO_VALUE se actualiza a 30, solo necesitas construir AssemblyA.No es necesario volver a compilar todos los clientes.

Entonces, si está seguro de que el valor de la constante no cambiará, utilice un const.

public const int CM_IN_A_METER = 100;

Pero si tiene una constante que puede cambiar (p. ej.w.r.t.precisión)..o en caso de duda, utilice un readonly.

public readonly float PI = 3.14;

Actualizar:Aku necesita una mención porque él señaló esto primero.También necesito conectar dónde aprendí esto. C# efectivo: Bill Wagner

Otros consejos

¡Hay un problema con las constantes!Si hace referencia a una constante de otro ensamblado, su valor se compilará directamente en el ensamblado que llama.De esa manera, cuando actualice la constante en el ensamblado al que se hace referencia, ¡no cambiará en el ensamblado que llama!

Constantes

  • Las constantes son estáticas por defecto
  • Deben tener un valor en el momento de la compilación (puede tener, por ejemplo,3.14 * 2, pero no puede llamar a métodos)
  • Podría declararse dentro de funciones
  • Se copian en cada ensamblado que los utiliza (cada ensamblado obtiene una copia local de los valores)
  • Se puede utilizar en atributos.

Campos de instancia de solo lectura

  • Debe tener un valor establecido, cuando el constructor salga
  • Se evalúan cuando se crea la instancia.

Campos estáticos de solo lectura

  • Se evalúan cuando la ejecución del código llega a la referencia de clase (cuando se crea una nueva instancia o se ejecuta un método estático)
  • Debe tener un valor evaluado cuando finalice el constructor estático.
  • No se recomienda poner ThreadStaticAttribute en estos (los constructores estáticos se ejecutarán en un solo subproceso y establecerán el valor de su subproceso;todos los demás hilos tendrán este valor sin inicializar)

Solo para agregar, ReadOnly para tipos de referencia solo hace que la referencia sea de solo lectura, no los valores.Por ejemplo:

public class Const_V_Readonly
{
  public const int I_CONST_VALUE = 2;
  public readonly char[] I_RO_VALUE = new Char[]{'a', 'b', 'c'};

  public UpdateReadonly()
  {
     I_RO_VALUE[0] = 'V'; //perfectly legal and will update the value
     I_RO_VALUE = new char[]{'V'}; //will cause compiler error
  }
}

esto lo explica.Resumen:const debe inicializarse en el momento de la declaración, readonly puede inicializarse en el constructor (y por lo tanto tener un valor diferente según el constructor utilizado).

EDITAR:Vea el truco de Gishu arriba para ver la sutil diferencia.

const:No se puede cambiar en ningún lado.

readonly:Este valor sólo se puede cambiar en el constructor.No se puede cambiar en funciones normales.

Hay un pequeño problema con el modo de solo lectura.Un campo de solo lectura se puede configurar varias veces dentro de los constructores.Incluso si el valor se establece en dos constructores encadenados diferentes, todavía está permitido.


public class Sample {
    private readonly string ro;

    public Sample() {
        ro = "set";
    }

    public Sample(string value) : this() {
        ro = value; // this works even though it was set in the no-arg ctor
    }
}

Un miembro constante se define en tiempo de compilación y no se puede cambiar en tiempo de ejecución.Las constantes se declaran como un campo, utilizando el const palabra clave y deben inicializarse a medida que se declaran.

public class MyClass
{
    public const double PI1 = 3.14159;
}

A readonly El miembro es como una constante en el sentido de que representa un valor que no cambia.La diferencia es que un readonly El miembro se puede inicializar en tiempo de ejecución, en un constructor, además de poder inicializarse a medida que se declaran.

public class MyClass1
{
     public readonly double PI2 = 3.14159;

     //or

     public readonly double PI3;

     public MyClass2()
     {
         PI3 = 3.14159;
     }
}

constante

  • No pueden ser declarados como static (son implícitamente estáticos)
  • El valor de la constante se evalúa en tiempo de compilación.
  • las constantes se inicializan solo en la declaración

solo lectura

  • Pueden ser a nivel de instancia o estáticos.
  • El valor se evalúa en tiempo de ejecución.
  • solo lectura se puede inicializar en una declaración o mediante código en el constructor

Una constante es una constante en tiempo de compilación, mientras que solo lectura permite calcular un valor en tiempo de ejecución y establecerlo en el constructor o inicializador de campo.Por lo tanto, una 'const' siempre es constante pero 'readonly' es de solo lectura una vez que se asigna.

Eric Lippert del equipo de C# tiene más información sobre diferentes tipos de inmutabilidad

Aquí hay otro enlace lo que demuestra que const no es una versión segura ni relevante para los tipos de referencia.

Resumen:

  • El valor de su propiedad const se establece en tiempo de compilación y no puede cambiar en tiempo de ejecución
  • Const no se puede marcar como estático: la palabra clave indica que son estáticos, a diferencia de los campos de solo lectura que sí pueden.
  • Const no puede ser nada excepto tipos de valor (primitivos)
  • La palabra clave de solo lectura marca el campo como inmodificable.Sin embargo, la propiedad se puede cambiar dentro del constructor de la clase.
  • La palabra clave de solo lectura también se puede combinar con static para que actúe de la misma manera que una constante (al menos en la superficie).Hay una marcada diferencia cuando nos fijamos en el IL entre los dos.
  • Los campos constantes están marcados como "literales" en IL, mientras que solo lectura es "initonly"

Solo lectura :El valor se puede cambiar a través de Ctor en tiempo de ejecución.Pero no a través de la función miembro

Constante :Por estática predeterminada.El valor no se puede cambiar desde ningún lugar (Ctor, Función, tiempo de ejecución, etc., en ningún lugar)

Otro problema más:Los valores de solo lectura se pueden cambiar mediante un código "tortuento" mediante reflexión.

var fi = this.GetType()
             .BaseType
             .GetField("_someField", 
                       BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(this, 1);

¿Puedo cambiar un campo privado heredado de solo lectura en C# usando la reflexión?

creo que un const El valor es el mismo para todos los objetos (y debe inicializarse con una expresión literal), mientras que readonly puede ser diferente para cada instanciación...

Uno de los miembros del equipo de nuestra oficina brindó la siguiente orientación sobre cuándo usar constante, estático y de solo lectura:

  • Usar constante cuando tienes una variable de un tipo, puedes saber en tiempo de ejecución (string literal, int, double, enums,...) que quieres que todas las instancias o consumidores de una clase tengan acceso a donde el valor no debe cambiar.
  • Usar estático cuando tiene datos a los que desea que todas las instancias o consumidores de una clase tengan acceso donde el valor puede cambiar.
  • Usar sólo lectura estática cuando tienes una variable de un tipo que no puedes saber en tiempo de ejecución (objetos) quieres que todas las instancias o consumidores de una clase tengan acceso a donde el valor no debe cambiar.
  • Usar solo lectura cuando tenga una variable de nivel de instancia, sabrá en el momento de la creación del objeto que no debe cambiar.

Una nota final:un campo constante es estático, pero lo contrario no es cierto.

Ambos son constantes, pero también hay una constante disponible en tiempo de compilación.Esto significa que un aspecto de la diferencia es que puedes usar variables constantes como entrada para constructores de atributos, pero no variables de solo lectura.

Ejemplo:

public static class Text {
  public const string ConstDescription = "This can be used.";
  public readonly static string ReadonlyDescription = "Cannot be used.";
}

public class Foo 
{
  [Description(Text.ConstDescription)]
  public int BarThatBuilds {
    { get; set; }
  }

  [Description(Text.ReadOnlyDescription)]
  public int BarThatDoesNotBuild {
    { get; set; }
  }
}

Las variables marcadas const son poco más que macros #define fuertemente tipadas; en el momento de la compilación, las referencias de variables const se reemplazan con valores literales en línea.Como consecuencia, de esta forma sólo se pueden utilizar ciertos tipos de valores primitivos integrados.Las variables marcadas como de solo lectura se pueden configurar, en un constructor, en tiempo de ejecución y su carácter de solo lectura también se aplica durante el tiempo de ejecución.Hay un costo de rendimiento menor asociado con esto, pero significa que puede usar solo lectura con cualquier tipo (incluso tipos de referencia).

Además, las variables constantes son inherentemente estáticas, mientras que las variables de solo lectura pueden ser específicas de una instancia si se desea.

Otro entendido.

Dado que const realmente solo funciona con tipos de datos básicos, si desea trabajar con una clase, es posible que se sienta "obligado" a usar ReadOnly.Sin embargo, ¡cuidado con la trampa!Solo lectura significa que no puede reemplazar el objeto con otro objeto (no puede hacer que haga referencia a otro objeto).Pero cualquier proceso que tenga una referencia al objeto es libre de modificar los valores. adentro ¡el objeto!

Así que no se confunda pensando que ReadOnly implica que un usuario no puede cambiar las cosas.No existe una sintaxis simple en C# para evitar que una creación de instancias de una clase cambie sus valores internos (hasta donde yo sé).

Existe una diferencia notable entre los campos constantes y de solo lectura en C#.Net

const es estático por defecto y debe inicializarse con un valor constante, que no se puede modificar más adelante.El cambio de valor tampoco está permitido en los constructores.No se puede utilizar con todos los tipos de datos.Por ejemplo, DateTime.No se puede utilizar con el tipo de datos DateTime.

public const DateTime dt = DateTime.Today;  //throws compilation error
public const string Name = string.Empty;    //throws compilation error
public readonly string Name = string.Empty; //No error, legal

readonly se puede declarar como estático, pero no es necesario.No es necesario inicializar en el momento de la declaración.Su valor se puede asignar o cambiar mediante el constructor.Por lo tanto, ofrece ventajas cuando se utiliza como miembro de una clase de instancia.Dos instancias diferentes pueden tener diferentes valores de campo de solo lectura.Por ejemplo -

class A
{
    public readonly int Id;

    public A(int i)
    {
        Id = i;
    }
}

Luego, el campo de solo lectura se puede inicializar con valores instantáneos específicos, de la siguiente manera:

A objOne = new A(5);
A objTwo = new A(10);

Aquí, la instancia objOne tendrá un valor de campo de solo lectura de 5 y objTwo tendrá 10.Lo cual no es posible usando const.

Una constante se compilará en el consumidor como un valor literal, mientras que la cadena estática servirá como referencia al valor definido.

Como ejercicio, intente crear una biblioteca externa y consumirla en una aplicación de consola, luego modifique los valores en la biblioteca y vuelva a compilarla (sin volver a compilar el programa consumidor), coloque la DLL en el directorio y ejecute el EXE manualmente, debería encontrar que la cadena constante no cambia.

Constante

Necesitamos proporcionar el valor al campo constante cuando esté definido.Luego, el compilador guarda el valor de la constante en los metadatos del ensamblado.Esto significa que una constante sólo se puede definir para el tipo primitivo como booleano, char, byte, etc.Las constantes siempre se consideran miembros estáticos, no miembros de instancia.

Solo lectura

Los campos de solo lectura solo se pueden resolver en tiempo de ejecución.Eso significa que podemos definir un valor para un valor usando el constructor para el tipo en el que se declara el campo.El compilador realiza la verificación de que los campos de solo lectura no se escriben mediante ningún método que no sea el constructor.

Más sobre ambos explicado aquí en este artículo

CONSTANTE

  1. La palabra clave const se puede aplicar a campos o variables locales.
  2. Debemos asignar el campo constante en el momento de la declaración.
  3. No se asigna memoria porque el valor constante está incrustado en el código IL después de la compilación.Es como encontrar todas las apariciones de la variable constante y reemplazarlas por su valor.Entonces, el código IL después de la compilación tendrá valores codificados en lugar de variables constantes.
  4. Las constantes en C# son estáticas por defecto.
  5. El valor es constante para todos los objetos.
  6. Hay un problema de control de versiones de DLL: esto significa que cada vez que cambiamos una variable o propiedad constante pública (de hecho, en teoría no se supone que deba cambiarse), se debe reconstruir cualquier otro DLL o ensamblado que utilice esta variable.
  7. Sólo los tipos integrados de C# se pueden declarar como constantes
  8. El campo constante no se puede pasar como parámetro de referencia o de salida

Solo lectura

  1. La palabra clave de solo lectura se aplica solo a campos, no a variables locales.
  2. Podemos asignar un campo de solo lectura en el momento de la declaración o en el constructor, no en ningún otro método.
  3. memoria dinámica asignada para campos de solo lectura y podemos obtener el valor en tiempo de ejecución.
  4. Solo lectura pertenece al objeto creado al que se accede a través de una única instancia de clase.Para convertirlo en miembro de la clase, debemos agregar la palabra clave estática antes de solo lectura.
  5. El valor puede ser diferente según el constructor utilizado (ya que pertenece al objeto de la clase)
  6. Si declara un tipo no primitivo (tipo de referencia) como de solo lectura, la referencia es inmutable, no el objeto que contiene.
  7. Dado que el valor se obtiene en tiempo de ejecución, no hay ningún problema de control de versiones de dll con campos/propiedades de solo lectura.
  8. Podemos pasar el campo de solo lectura como parámetro ref o out en el contexto del constructor.

Principalmente;puede asignar un valor a un campo estático de solo lectura a un valor no constante en tiempo de ejecución, mientras que a una constante se le debe asignar un valor constante.

A const tiene que ser codificado, mientras readonly puede ser establecido en el constructor de la clase.

Const y readonly son similares, pero no son exactamente iguales.Un campo constante es una constante en tiempo de compilación, lo que significa que ese valor se puede calcular en tiempo de compilación.Un campo de solo lectura habilita escenarios adicionales en los que se debe ejecutar algo de código durante la construcción del tipo.Después de la construcción, un campo de solo lectura no se puede cambiar.

Por ejemplo, los miembros constantes se pueden usar para definir miembros como:

struct Test
{
    public const double Pi = 3.14;
    public const int Zero = 0;
}

ya que valores como 3.14 y 0 son constantes en tiempo de compilación.Sin embargo, considere el caso en el que define un tipo y desea proporcionar algunas instancias prefabricadas del mismo.Por ejemplo, es posible que desee definir una clase de Color y proporcionar "constantes" para colores comunes como negro, blanco, etc.No es posible hacer esto con miembros constantes, ya que los lados derechos no son constantes en tiempo de compilación.Se podría hacer esto con miembros 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 = r;
        green = g;
        blue = b;
    }
}

pero entonces no hay nada que impida que un cliente de Color juegue con él, tal vez intercambiando los valores de Blanco y Negro.No hace falta decir que esto causaría consternación a otros clientes de la clase Color.La característica de "solo lectura" soluciona este escenario.Simplemente introduciendo la palabra clave readonly en las declaraciones, preservamos la inicialización flexible y al mismo tiempo evitamos que el código del cliente se pierda.

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 = r;
        green = g;
        blue = b;
    }
}

Es interesante observar que los miembros constantes son siempre estáticos, mientras que un miembro de solo lectura puede ser estático o no, como un campo normal.

Es posible utilizar una sola palabra clave para estos dos propósitos, pero esto genera problemas de versiones o de rendimiento.Supongamos por un momento que usamos una sola palabra clave para esto (const) y un desarrollador escribió:

public class A
{
    public static const C = 0;
}

y un desarrollador diferente escribió código que se basaba en A:

public class B
{
    static void Main() {
        Console.WriteLine(A.C);
    }
}

Ahora bien, ¿puede el código generado confiar en el hecho de que A.C es una constante en tiempo de compilación?Es decir, ¿se puede simplemente reemplazar el uso de A.C por el valor 0?Si dice "sí" a esto, entonces eso significa que el desarrollador de A no puede cambiar la forma en que se inicializa A.C; esto ata las manos del desarrollador de A sin permiso.Si responde "no" a esta pregunta, se perderá una optimización importante.Quizás el autor de A esté seguro de que A.C siempre será cero.El uso de const y readonly permite al desarrollador de A especificar la intención.Esto permite un mejor comportamiento de control de versiones y también un mejor rendimiento.

ReadOnly: el valor se inicializará solo una vez desde el constructor de la clase.
constante:Se puede inicializar en cualquier función pero sólo una vez.

La diferencia es que el valor de un campo estático de solo lectura se establece en tiempo de ejecución, por lo que puede tener un valor diferente para diferentes ejecuciones del programa.Sin embargo, el valor de un campo constante se establece en una constante de tiempo de compilación.

Recordar:Para los tipos de referencia, en ambos casos (estático y de instancia), el modificador de solo lectura solo le impide asignar una nueva referencia al campo.Específicamente no hace inmutable el objeto al que apunta la referencia.

Para obtener más información, consulte las Preguntas frecuentes de C# sobre este tema:http://blogs.msdn.com/csharpfaq/archive/2004/12/03/274791.aspx

Las variables constantes se declaran e inicializan en tiempo de compilación.El valor no se puede cambiar posteriormente.Las variables de solo lectura se inicializarán únicamente desde el constructor estático de la clase.Solo lectura se usa solo cuando queremos asignar el valor en tiempo de ejecución.

Una cosa que añadir a lo que la gente ha dicho anteriormente.Si tiene un ensamblado que contiene un valor de solo lectura (p. ej.sólo lectura MaxFooCount = 4;), puede cambiar el valor que ven los ensamblados que llaman enviando una nueva versión de ese ensamblado con un valor diferente (p. ej.sólo lectura MaxFooCount = 5;)

Pero con una constante, se incluiría en el código de la persona que llama cuando se compila la persona que llama.

Si ha alcanzado este nivel de dominio de C#, está listo para leer el libro de Bill Wagner, Effective C#:50 formas específicas de mejorar su C# que responde esta pregunta en detalle (y otras 49 cosas).

La diferencia clave es que Const es el equivalente en C de #DEFINE.El número literalmente se sustituye por el precompilador.En realidad, solo lectura se trata como una variable.

Esta distinción es especialmente relevante cuando el Proyecto A depende de una constante Pública del Proyecto B.Supongamos que el público cambia constantemente.Ahora su elección de constante/solo lectura afectará el comportamiento en el proyecto A:

constante:El proyecto A no captura el nuevo valor (a menos que se vuelva a compilar con la nueva constante, por supuesto) porque se compiló con las constantes sustituidas.

Solo lectura:El proyecto A siempre le pedirá al proyecto B el valor de su variable, por lo que recogerá el nuevo valor de la constante pública en B.

Honestamente, te recomendaría que uses solo lectura para casi todo, excepto constantes verdaderamente universales (p. ej.Pi, pulgadas_a_centímetros).Para cualquier cosa que pueda cambiar, recomiendo usar solo lectura.

Espero que esto ayude, Alan.

En palabras simples, Const es tiempo de compilación y solo lectura es tiempo de ejecución.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top