2011-07-04 12 views
7

Estoy leyendo el blog de Eric Liperts sobre Mutating Readonly Structs y veo muchas referencias aquí en SO a este blog como argumento por qué los tipos de valores deben ser inmutables. Pero todavía hay algo que no está claro, dice que cuando se accede tipo de valor que siempre obtenga la copia del mismo y aquí está el ejemplo:tipos de valores inmutables

struct Mutable 
{ 
    private int x; 
    public int Mutate() 
    { 
     this.x = this.x + 1; 
     return this.x; 
    } 
} 

class Test 
{ 
    public readonly Mutable m = new Mutable(); 
    static void Main(string[] args) 
    { 
     Test t = new Test(); 
     System.Console.WriteLine(t.m.Mutate()); 
     System.Console.WriteLine(t.m.Mutate()); 
     System.Console.WriteLine(t.m.Mutate()); 
    } 
} 

Y la pregunta es ¿por qué cuando cambio la

public readonly Mutable m = new Mutable(); 

a

public Mutable m = new Mutable(); 

todo empieza a trabajar es de esperar .

Por favor, puede explicar más claro por qué los tipos de valores deben ser inmutables. Sé que es bueno para la seguridad de la hebra, pero en este caso, puede aplicarse a los tipos de referencia.

+0

No sabría cómo responder esto sin solo copiar y pegar más citas de la misma publicación de blog a la que se ha vinculado. 'm' siendo' readonly' es lo que hace 't.m' un valor, que, al no ser una variable, se coloca en una variable temporal, y es esta variable temporal la que es' this' dentro del método 'Mutate'. Quitar 'readonly', y los factores restantes ya no se aplican, por lo que' this' dentro de 'Mutate' puede ser' m'. –

Respuesta

4

Las estructuras con métodos de mutación se comportan de manera extraña en varias situaciones.

El ejemplo que ya descubrió es un campo de solo lectura. Es necesaria una copia defensiva porque no desea mutar un campo de solo lectura.

Pero también cuando se usa como propiedades. Una vez más, ocurre una copia implícita, y solo la copia está mutada. Incluso si la propiedad tiene un colocador.

struct Mutable 
{ 
    private int x; 
    public int Mutate() 
    { 
     this.x = this.x + 1; 
     return this.x; 
    } 
} 

Mutable property{get;set;} 

void Main() 
{ 
    property=new Mutable(); 
    property.Mutate().Dump();//returns 1 
    property.Mutate().Dump();//returns 1 :(
} 

Esto muestra que los métodos de mutación son problemáticos en las estructuras. Pero no muestra que una estructura mutable con campos públicos o propiedades que tienen un setter sea problemática.

2

La seguridad de la rosca es una razón técnica clara. Se aplica tanto a los tipos de valores como a los tipos de referencia (ver System.String).

La pauta más general "los tipos de valores deben ser inmutables" es diferente. Se trata de la legibilidad del código, y proviene principalmente de la confusión que pueden causar los valores mutables. Este fragmento de código es solo un ejemplo. La mayoría de la gente no esperaría el 1,1,1 resultado.

+0

Sí, pero aun así, si no es de solo lectura, todo funcionará como se esperaba. Más general, la pregunta no está en eso, ¿pero es por eso que los tipos de valores sugeridos son inmutables? – NDeveloper

+0

@Ndev: Creo que respondí la pregunta más general (por qué). @Damien ha analizado la muestra del código. –

+0

pero ¿no sería la legibilidad la misma que para los tipos de ref? O quiere decir que este es el asunto por el que pasan una referencia, por lo que pueden mutar ... – NDeveloper

2

No sé C#, por lo que intentaré responder a la segunda parte de su pregunta.

¿Por qué los tipos de valores deben ser inmutables?

Hay dos tipos de objetos de dominio Driven punto de vista del diseño: objetos

  • valor/tipos - su identidad está determinada por su valor (por ejemplo, números: 2 es siempre 2 - una identidad de el número dos es siempre el mismo, así que 2 == 2 siempre es verdadero)
  • entidades (tipos de referencia) - pueden consistir en otros tipos de valores y su identidad está determinada por su propia identidad (p. ej .: personas: incluso si era un hombre exactamente igual que usted, no sería usted)

Si los tipos de valores son mutables, imagine lo que podría suceder si fuera posible cambiar el valor del número dos: 2 == 1 + 1 no se garantizará como verdadero.

Consulte estos enlaces para más:

+0

Aunque los tipos de valores mutables son problemáticos, no es tan malo como suena en su respuesta. El problema generalmente no es que pueda mutar algo que no debería, sino que accidentalmente mutee una copia temporal en lugar de mutar. – CodesInChaos

0

Creo que lo más complicado de este ejemplo es que se podría argumentar que no debería ser posible. Hiciste una instancia de Mutable de solo lectura y, sin embargo, puedes cambiar su valor a través de la función Mutate(), violando así el concepto de inmutabilidad, en cierto sentido. Estrictamente hablando, sin embargo, funciona porque el campo privado x no es de solo lectura.Si haces un simple cambio en la clase mutable entonces la inmutabilidad de hecho se hará cumplir:

private readonly int x; 

Entonces la función Mutate() producirá un error de compilación.

El ejemplo muestra claramente cómo funciona copy-by-value en el contexto de variables de solo lectura. Siempre que llame a m, está creando una copia de la instancia, a diferencia de una copia de una referencia a la instancia; la última ocurriría si Mutable fuera una clase en lugar de una estructura.

Como cada vez que llamas m estás llamando 1) una copia de la instancia, y 2) una copia de una instancia que es de solo lectura, el valor de x es siempre será 0 en el momento de la copia tiene lugar. Cuando llamas a Mutate() en la copia, incrementa x a 1, lo cual funciona porque x mismo NO es de solo lectura. Pero la próxima vez que llame a Mutate() todavía lo está llamando en el valor predeterminado original de 0. Como dice en el artículo "m es inmutable, pero la copia no lo es". Cada copia de la instancia original tendrá x como 0 porque el objeto que se está copiando nunca cambia, mientras que sus copias se pueden cambiar.

Quizás eso ayude.

Cuestiones relacionadas