¿Cuáles son los beneficios de marcar un campo como 'readonly' en C#?


¿Cuáles son los beneficios de tener una variable miembro declarada como solo lectura? ¿Es solo la protección contra alguien que cambia durante el ciclo de vida de la clase o hay alguna mejora de la velocidad del compilador debido a esta palabra clave

 221
Author: Eddie, 2008-11-10

14 answers

La palabra clave readonly se usa para declarar una variable miembro como constante, pero permite que el valor se calcule en tiempo de ejecución. Esto difiere de una constante declarada con el modificador const, que debe tener su valor establecido en tiempo de compilación. Usando readonly puede establecer el valor del campo en la declaración o en el constructor del objeto del que el campo es miembro.

También úselo si no desea tener que recompilar archivos DLL externos que hacen referencia a la constante (ya que obtiene reemplazado en tiempo de compilación).

 109
Author: Bill the Lizard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-27 21:51:37

No creo que haya ninguna ganancia de rendimiento al usar un campo de solo lectura. Es simplemente una comprobación para asegurarse de que una vez que el objeto está completamente construido, ese campo no se puede apuntar a un nuevo valor.

Sin embargo, "readonly" es muy diferente de otros tipos de semántica de solo lectura porque es forzada en tiempo de ejecución por el CLR. La palabra clave readonly compila hasta .initonly que es verificable por el CLR.

La verdadera ventaja de esta palabra clave es generar datos inmutables estructura. Las estructuras de datos inmutables por definición no se pueden cambiar una vez construidas. Esto hace que sea muy fácil razonar sobre el comportamiento de una estructura en tiempo de ejecución. Por ejemplo, no hay peligro de pasar una estructura inmutable a otra porción aleatoria de código. No pueden cambiarlo nunca para que puedas programar de manera confiable contra esa estructura.

Aquí hay una buena entrada sobre uno de los beneficios de la inmutabilidad: Threading

 160
Author: JaredPar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-14 15:24:11

No hay beneficios aparentes de rendimiento al usar readonly, al menos ninguno que haya visto mencionado en ningún lugar. Es solo para hacer exactamente lo que sugiere, para evitar la modificación una vez que se ha inicializado.

Así que es beneficioso ya que te ayuda a escribir código más robusto y legible. El verdadero beneficio de cosas como esta viene cuando estás trabajando en un equipo o para mantenimiento. Declarar algo como readonly es similar a poner un contrato para el uso de esa variable en el codificar. Piense en ello como agregar documentación de la misma manera que otras palabras clave como internal o private, está diciendo "esta variable no debe modificarse después de la inicialización", y además está imponiéndola.

Así que si creas una clase y marcas algunas variables de miembro readonly por diseño, entonces evitarás que tú u otro miembro del equipo cometa un error más adelante cuando estén expandiendo o modificando tu clase. En mi opinión, ese es un beneficio que vale la pena tener (a un pequeño costo de complejidad adicional del lenguaje como doofledorfer menciona en los comentarios).

 58
Author: Xiaofu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-11 03:44:05

Para ponerlo en términos muy prácticos:

Si usa una const en dll A y dll B hace referencia a esa const, el valor de esa const se compilará en dll B. Si vuelve a implementar dll A con un nuevo valor para esa const, dll B seguirá utilizando el valor original.

Si usa un readonly en las referencias dll A y dll B que readonly, ese readonly siempre se buscará en tiempo de ejecución. Esto significa que si vuelve a implementar dll A con un nuevo valor para ese readonly, dll B usará ese nuevo valor.

 39
Author: Daniel Auger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-23 19:20:50

Hay un caso potencial donde el compilador puede hacer una optimización de rendimiento basada en la presencia de la palabra clave readonly.

Esto solo se aplica si el campo readonly también está marcado como static. En ese caso, el compilador JIT puede asumir que este campo estático nunca cambiará. El compilador JIT puede tener esto en cuenta al compilar los métodos de la clase.

Ejemplo típico: su clase podría tener un campo estático readonly IsDebugLoggingEnabled que se inicializa en el constructor (por ejemplo, basado en un archivo de configuración). Una vez que los métodos reales son compilados JIT, el compilador puede ommit partes enteras del código cuando el registro de depuración no está habilitado.

No he comprobado si esta optimización está realmente implementada en la versión actual del compilador JIT, así que esto es solo especulación.

 13
Author: Kristof Verbiest,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-25 09:29:34

Tenga en cuenta que readonly solo se aplica al valor en sí, por lo que si está utilizando un tipo de referencia, readonly solo protege la referencia de cambios. El estado de la instancia no está protegido por readonly.

 6
Author: Brian Rasmussen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-23 19:29:14

No olvide que hay una solución alternativa para obtener los campos readonly establecidos fuera de cualquier constructor usando parámetros out.

Un poco desordenado pero:

private readonly int _someNumber;
private readonly string _someText;

public MyClass(int someNumber) : this(data, null)
{ }

public MyClass(int someNumber, string someText)
{
    Initialise(out _someNumber, someNumber, out _someText, someText);
}

private void Initialise(out int _someNumber, int someNumber, out string _someText, string someText)
{
    //some logic
}

Más discusión aquí: http://www.adamjamesnaylor.com/2013/01/23/Setting-Readonly-Fields-From-Chained-Constructors.aspx

 5
Author: Adam Naylor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-23 23:22:35

Si tiene un valor pre definido o pre calculado que necesita permanecer igual durante todo el programa, entonces debe usar constant, pero si tiene un valor que necesita ser proporcionado en el tiempo de ejecución, pero una vez asignado debe permanecer igual durante todo el programa, debe usar readonly. por ejemplo, si tiene que asignar la hora de inicio del programa o tiene que almacenar un valor proporcionado por el usuario en la inicialización del objeto y tiene que restringirlo de cambios adicionales, debe usar readonly.

 2
Author: waqar ahmed,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-28 10:59:23

Tenga cuidado con los arrays de solo lectura privados. Si estos son expuestos un cliente como un objeto (usted podría hacer esto para COM interop como lo hice) el cliente puede manipular los valores de matriz. Use el método Clone () cuando devuelva una matriz como un objeto.

 1
Author: Michael,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-10 12:04:54

readonly se puede inicializar en la declaración u obtener su valor solo del constructor. A diferencia de const tiene que ser inicializado y declarado al mismo tiempo. readonly tiene todo const has, más inicialización del constructor

Código https://repl.it/HvRU/1

using System;

class MainClass {
    public static void Main (string[] args) {

        Console.WriteLine(new Test().c);
        Console.WriteLine(new Test("Constructor").c);
        Console.WriteLine(new Test().ChangeC()); //Error A readonly field 
        // `MainClass.Test.c' cannot be assigned to (except in a constructor or a 
        // variable initializer)
    }


    public class Test {
        public readonly string c = "Hello World";
        public Test() {

        }

        public Test(string val) {
          c = val;
        }

        public string ChangeC() {
            c = "Method";
            return c ;
        }
    }
}
 1
Author: Mina Gabriel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-17 03:29:18

Sorprendentemente, readonly puede resultar en código más lento, como Jon Skeet descubrió al probar su biblioteca de tiempo Noda. En este caso, una prueba que se ejecutó en 20 segundos tomó solo 4 segundos después de eliminar readonly.

Https://codeblog.jonskeet.uk/2014/07/16/micro-optimization-the-surprising-inefficiency-of-readonly-fields/

 1
Author: Neil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-17 16:57:07

Puede haber un beneficio de rendimiento en WPF, ya que elimina la necesidad de costosas DependencyProperties. Esto puede ser especialmente útil con colecciones

 0
Author: Shane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-20 23:51:43

Otra parte interesante del uso del marcado readonly puede ser proteger el campo de la inicialización en singleton.

Por ejemplo, en el código de csharpindepth:

public sealed class Singleton
{
    private static readonly Lazy<Singleton> lazy =
        new Lazy<Singleton>(() => new Singleton());

    public static Singleton Instance { get { return lazy.Value; } }

    private Singleton()
    {
    }
}

Readonly juega un papel pequeño de proteger el campo Singleton de ser inicializado dos veces. Otro detalle es que para el escenario mencionado no puede usar const porque const fuerza la creación durante el tiempo de compilación, pero singleton hace la creación en tiempo de ejecución.

 0
Author: Yura Zaletskyy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-09 18:47:22

Añadiendo un aspecto básico para responder a esta pregunta:

Las propiedades

Se pueden expresar como readonly omitiendo el operador set. Por lo tanto, en la mayoría de los casos no necesitará agregar la palabra clave readonly a las propiedades:

public int Foo { get; }  // a readonly property

En contraste con eso: Los campos necesitan la palabra clave readonly para lograr un efecto similar:

public readonly int Foo; // a readonly field

Por lo tanto, una ventaja de marcar un campo como readonly puede ser lograr un nivel de protección contra escritura similar como una propiedad sin el operador set, sin tener que cambie el campo a una propiedad, si por alguna razón, que se desea.

 0
Author: Chris 14214,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-17 17:00:55