¿Cuál es la diferencia entre const y readonly en C #?

1506

¿Cuál es la diferencia entre consty readonlyen C #?

¿Cuándo usarías uno sobre el otro?

2
1414

Aparte de la aparente diferencia de

  • tener que declarar el valor en el momento de una definición para un constVS, los readonlyvalores se pueden calcular dinámicamente, pero deben asignarse antes de que el constructor salga ... después de eso, se congela.
  • constson implícitamente static. Utiliza una ClassName.ConstantNamenotación para acceder a ellos.

Hay una sutil diferencia. 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;
  }
}

AssemblyBhace referencia AssemblyAy utiliza estos valores en el código. Cuando esto se compila:

  • en el caso del constvalor, es como buscar-reemplazar. El valor 2 se 'hornea' en el AssemblyB'IL'. Esto significa que si mañana actualizo I_CONST_VALUEa 20, AssemblyBtodavía tendrían 2 hasta que lo recompile .
  • en el caso del readonlyvalor, es como un refa una ubicación de memoria. El valor no se incluye en AssemblyBel IL. Esto significa que si se actualiza la ubicación de la memoria, AssemblyBobtiene el nuevo valor sin volver a compilar. Entonces, si I_RO_VALUEse actualiza a 30, solo necesita compilar AssemblyAy no es necesario volver a compilar todos los clientes.

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

public const int CM_IN_A_METER = 100;

Pero si tiene una constante que puede cambiar (precisión egwrt) ... o en caso de duda, use a readonly.

public readonly float PI = 3.14;

Actualización: Aku necesita una mención porque señaló esto primero. También necesito conectar donde aprendí esto: C # efectivo - Bill Wagner

8
  • 94
    El staticpunto parece ser el punto más importante y útil -consts are implicitly staticLCJ 21 de enero de 2013 a las 14:00
  • 34
    La parte sobre valores de referencia es la más importante. Los valores de constante se pueden optimizar. CodingBarfield 5 de junio de 2013 a las 7:03
  • 27
    readonlylas variables se pueden cambiar fuera del constructor (reflexión). Es solo el compilador el que intenta impedirle modificar la var fuera del constructor. Bitterblue 5 de junio de 2013 a las 14:10
  • 14
    Las readonlyvariables @ mini-me no pueden cambiarse una vez que el constructor ha terminado, incluso a través de la reflexión. El tiempo de ejecución no hace cumplir esto. El tiempo de ejecución tampoco impone que no cambie string.Emptya "Hello, world!", pero aún así no afirmaría que esto lo hace string.Emptymodificable, o que el código no debería asumir que string.Emptysiempre será una cadena de longitud cero. user743382 14/04/2014 a las 11:55
  • 10
    blogs.msmvps.com/jonskeet/2014/07/16/… es una lectura interesante solo el costo general de readonlyCAD bloke 5 de agosto de 2014 a las 21:52
300

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

1
  • 14
    En la descompilación (Reflector, ILSpy, ..) nadie hace referencia NUNCA NUNCA a una constante, sin importar el mismo ensamblado u otro ensamblado, por lo que no puede analizar el uso de una constante en el código compilado en absoluto. springy76 19 de agosto de 2016 a las 13:02
175

Constantes

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

Campos de instancia de solo lectura

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

Campos de solo lectura estáticos

  • 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 en el momento en que se realiza el constructor estático
  • No se recomienda poner ThreadStaticAttribute en estos (los constructores estáticos se ejecutarán en un solo hilo y establecerán el valor para su hilo; todos los demás hilos tendrán este valor sin inicializar)
0
66

Solo para agregar, readonlypara los tipos de referencia solo hace que la referencia solo lea, 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
  }
}
3
  • ¿Existe algún otro tipo de referencia stringque no pueda utilizar como constante? springy76 19 de agosto de 2016 a las 13:02
  • Puede tener constcon tipos de referencia distintos de cadena, pero la constante solo puede tener el valor null. Mike Rosoft 27/04/18 a las 14:28
  • @ user1333 Estás confundiendo un valor desreferenciado con el valor referenciado. La instancia en su ejemplo, el valor de solo lectura, es a Char[]. El valor que está cambiando en la primera declaración de actualización es el contenido al que se accede a través de la referencia, no la referencia en sí. Suncat2000 22 de septiembre de 2020 a las 12:46
45

Esto lo explica . Resumen: const debe inicializarse en el momento de la declaración, readonly se puede inicializar en el constructor (y por lo tanto tener un valor diferente dependiendo del constructor utilizado).

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

0
43

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

readonly: Este valor solo se puede cambiar en el constructor. No se puede cambiar en funciones normales.

0
36

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 la constpalabra clave y deben inicializarse como se declaran.

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

Un readonlymiembro es como una constante en el sentido de que representa un valor invariable. La diferencia es que un readonlymiembro 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 se pueden declarar como static(son implícitamente estáticas)
  • 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 estáticos o a nivel de instancia
  • El valor se evalúa en tiempo de ejecución.
  • readonly se puede inicializar en una declaración o por código en el constructor
2
  • 6
    No pueden ser estáticos , son estáticos. Debería dejar en claro si quiso decir que uno no puede declararstatic const int i = 0;nawfal 13/12-13 a las 20:21
  • ¿Puede explicar por qué constno se pueden hacer declaraciones dentro de los métodos? Minh Tran 29/10/2017 a las 17:38
30

Hay un pequeño problema con readonly. Un campo de solo lectura se puede establecer 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
    }
}
0
27

Una const es una constante en tiempo de compilación, mientras que readonly permite que se calcule un valor en tiempo de ejecución y se establezca en el constructor o en el inicializador de campo. Entonces, una 'const' es siempre 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.

16

Aquí hay otro enlace que demuestra cómo const no es seguro para la versión o 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 denota que son estáticos, a diferencia de los campos de solo lectura que pueden hacerlo.
  • Const no puede ser nada excepto tipos de valor (primitivos)
  • La palabra clave readonly marca el campo como inmutable. 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 estática para que actúe de la misma manera que una constante (al menos en la superficie). Hay una marcada diferencia cuando miras el IL entre los dos
  • Los campos const están marcados como "literal" en IL, mientras que readonly es "initonly"
0
15

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 defecto estático. El valor no se puede cambiar desde ningún lugar (Ctor, función, tiempo de ejecución, etc. en ningún lugar)

1
  • 2
    gracias por no hacerme leer 4 párrafos solo por estas dos conclusiones ...Don Cheadle 26/02/18 a las 19:11
12

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

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

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

9

Creo que un constvalor es el mismo para todos los objetos (y debe inicializarse con una expresión literal), mientras que readonlypuede ser diferente para cada instanciación ...

7

Ambos son constantes, pero una constante también está disponible en tiempo de compilación. Esto significa que un aspecto de la diferencia es que puede usar variables const como entrada para los 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; }
  }
}
6

Uno de los miembros del equipo en nuestra oficina brindó la siguiente guía sobre cuándo usar const, static y readonly:

  • Use const cuando tenga una variable de un tipo que pueda saber en tiempo de ejecución (string literal, int, double, enums, ...) que desea que todas las instancias o consumidores de una clase tengan acceso donde el valor no debería cambiar.
  • Utilice estático cuando tenga datos a los que desee que todas las instancias o consumidores de una clase tengan acceso donde el valor puede cambiar.
  • Utilice static readonly cuando tenga una variable de un tipo que no pueda conocer en tiempo de ejecución (objetos) y que desee que todas las instancias o consumidores de una clase tengan acceso donde el valor no debería cambiar.
  • Use readonly cuando tenga una variable de nivel de instancia que sabrá en el momento de la creación del objeto que no debería cambiar.

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

1
  • 1
    Creo que te refieres a "conversar". La inversa sería "un campo no constante no es estático". Lo cual puede ser cierto o no. Lo contrario, "un campo estático es (siempre) constante" no es cierto. Michael Blackburn 27/04/2016 a las 21:02
6

CONST

  1. La palabra clave const se puede aplicar a campos o variables locales
  2. Debemos asignar un campo constante en el momento de la declaración.
  3. No hay memoria asignada porque el valor constante está incrustado en el propio código IL después de la compilación. Es como buscar todas las apariciones de la variable const y reemplazarla por su valor. Entonces, el código IL después de la compilación tendrá valores codificados en lugar de las variables const
  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 const pública (de hecho, no se supone que se cambie teóricamente), cualquier otro dll o ensamblado que use esta variable debe ser reconstruido
  7. Solo 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, por lo que se accede solo a través de una instancia de clase. Para convertirlo en miembro de la clase, debemos agregar una palabra clave estática antes de readonly.
  5. El valor puede ser diferente según el constructor utilizado (ya que pertenece al objeto de la clase)
  6. Si declara tipos no primitivos (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 un campo de solo lectura como parámetros de referencia o de salida en el contexto del constructor.
6
  • cuando usar constoreadonly

    • const

      • constante de tiempo de compilación : constante absoluta , el valor se establece durante la declaración, está en el código IL mismo
    • readonly

      • constante de tiempo de ejecución : se puede configurar en el constructor / init a través del archivo de configuración, es decir App.config, pero una vez que se inicializa no se puede cambiar
5

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, solo ciertos tipos de valores primitivos incorporados se pueden usar de esta manera. Las variables marcadas como de solo lectura se pueden establecer, 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 const son inherentemente estáticas, mientras que las variables de solo lectura pueden ser específicas de la instancia si se desea.

1
  • Se agregó que los consts son macros #define fuertemente tipados . De lo contrario, podemos asustar a toda la gente de C o C ++. :-)Jason Baker 5 de ene. De 2009 a las 22:35
4

Existe una diferencia notable entre los campos const y readonly en C # .Net

const es estático por defecto y debe inicializarse con un valor constante, que no se puede modificar más adelante. Tampoco se permite el cambio de valor 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 usando constructor. Por lo tanto, da ventaja cuando se usa como miembro de clase de instancia. Dos instancias diferentes pueden tener un valor diferente de campo de solo lectura. Por ex -

class A
{
    public readonly int Id;

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

Luego, el campo de solo lectura se puede inicializar con valores específicos instantáneos, 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 como 5 y objTwo tiene 10. Lo cual no es posible usando const.

3

Otro gotcha .

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

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

1
  • Sí, eso es más un tema general. Si tiene una propiedad get only que expone una lista de matrices, aún puede modificar la lista de matrices. No puede establecer una lista de matrices diferente a esa propiedad, pero no puede evitar que el usuario modifique la lista de matrices. Gishu 17 de septiembre de 2008 a las 13:31
3

A consttiene que estar codificado de forma rígida , donde como readonlyse puede establecer en el constructor de la clase.

2

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 alterar los valores en la biblioteca y recompilarla (sin recompilar el programa consumidor), colocar la DLL en el directorio y ejecutar el EXE manualmente, debería encontrar que la cadena constante no cambia.

6
  • Sinceramente dudo que sea cierto ... Iré a comprobarlo. ljs 8 de septiembre de 2009 a las 12:23
  • esta es una de las 50 formas específicas de mejorar su C # - amazon.co.uk/Effective-Specific-Ways-Improve-Your/dp/0321245660/…Russ Cam 8 de septiembre de 2009 a las 12:24
  • my.safaribooksonline.com/0321245660/…Russ Cam 8 de septiembre de 2009 a las 12:27
  • @ Andrew Hare: sí, acabo de comprobarlo. Estoy muy sorprendido, eso es un verdadero problema, realmente estoy muy sorprendido por eso, ¡asombrado de que sea el caso ...! ljs 8 de septiembre de 2009 a las 12:29
  • Sin embargo, me opongo al uso de la palabra puntero aquí. No es un puntero, que es una referencia, y no es una diferencia en C # como se puede manipular punteros no administrados en modo no seguro por lo que es importante distinguir entre los dos. ljs 8 de septiembre de 2009 a las 12:31
2

Const y readonly son similares, pero no son exactamente iguales. Un campo const 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 algún 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 const 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 Color y proporcionar "constantes" para colores comunes como Negro, Blanco, etc. No es posible hacer esto con miembros const, 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 cambiando los valores de Blanco y Negro. No hace falta decir que esto causaría consternación a otros clientes de la clase Color. La función "solo lectura" aborda este escenario. Simplemente introduciendo la palabra clave readonly en las declaraciones, preservamos la inicialización flexible mientras 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 notar que los miembros const son siempre estáticos, mientras que un miembro de solo lectura puede ser estático o no, como un campo regular.

Es posible utilizar una sola palabra clave para estos dos propósitos, pero esto conduce a problemas de control de versiones o de rendimiento. Suponga 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ó un código que se basó en A:

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

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

2

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

2

La diferencia es que el valor de un campo de solo lectura estático 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 const se establece en una constante de tiempo de compilación.

Recuerde: para los tipos de referencia, en ambos casos (estático e 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

2

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

1

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

0

Una cosa para agregar a lo que la gente ha dicho anteriormente. Si tiene un ensamblado que contiene un valor de solo lectura (por ejemplo, MaxFooCount de solo lectura = 4;), puede cambiar el valor que ven los ensamblados que llaman enviando una nueva versión de ese ensamblado con un valor diferente (por ejemplo, MaxFooCount de solo lectura = 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 competencia en C #, está listo para el libro de Bill Wagner, C # efectivo: 50 formas específicas de mejorar su C #, que responde a esta pregunta en detalle (y otras 49 cosas).

0

La diferencia clave es que Const es el equivalente en C de #DEFINE. El número se sustituye literalmente 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. Suponga que la constante pública cambia. Ahora su elección de const / readonly afectará el comportamiento en el proyecto A:

Const: el proyecto A no captura el nuevo valor (a menos que se recompile con la nueva constante, por supuesto) porque fue compilado con las constantes sustituidas en.

ReadOnly: Project A siempre le pedirá al proyecto B su valor variable, por lo que tomará el nuevo valor de la constante pública en B.

Honestamente, le recomendaría que use readonly para casi todo, excepto las constantes verdaderamente universales (por ejemplo, Pi, Inches_To_Centimeters). Para cualquier cosa que pueda cambiar, digo use readonly.

Espero que esto ayude, Alan.

0

Const : Valor constante absoluto durante la vida útil de la aplicación.

Solo lectura : se puede cambiar en tiempo de ejecución.

1
  • 2
    Su definición de "solo lectura" que puede cambiar es errónea. Supongo que por "cambiar" querías decir "configurar", como "se puede configurar en tiempo de ejecución". Ahmed 26 de diciembre de 2019 a las 5:48