c# - cref - ¿Cuál es la diferencia entre estas dos variaciones de expresiones de inicializador de colección?
remarks c# (1)
He estado usando C # por un tiempo, pero recientemente noté que el comportamiento de una de mis pruebas de unidad cambió según la variación de la expresión de inicializador de colección que usé:
var object = new Class { SomeCollection = new List<int> { 1, 2, 3 } };
-
var object = new Class { SomeCollection = { 1, 2, 3 } };
Hasta este punto asumí que la segunda forma era solo azúcar sintáctica y era semánticamente equivalente a la primera forma. Sin embargo, cambiar entre estas dos formas resultó en que mi prueba de unidad fallada se pasara
El código de ejemplo a continuación demuestra esto:
void Main()
{
var foo1 = new Foo { Items = new List<int> { 1, 2, 3} };
var foo2 = new Foo { Items = { 1, 2, 3 } };
foo1.Dump();
foo2.Dump();
}
class Foo
{
public List<int> Items { get; set; }
}
Cuando ejecuto esto, la primera asignación funciona bien, pero la segunda resulta en una NullReferenceException
.
Mi intuición es que detrás de escena el compilador está tratando estas dos expresiones de la siguiente manera:
var foo1 = new Foo();
foo1.Items = new List<int> { 1, 2, 3 };
var foo2 = new Foo();
foo2.Items.Add(1);
foo2.Items.Add(2);
foo2.Items.Add(3);
¿Es ese supuesto exacto?
Sí, tu suposición es precisa. Si un inicializador de objetos solo tiene:
{
Property = { ... }
}
más bien que
{
Property = expression
}
luego no se usa el establecedor de la propiedad; se usa el captador , y luego se llama al método Add
o se establecen las propiedades dentro del valor devuelto. Asi que:
var foo = new Foo
{
Collection = { 1 }
Property =
{
Value = 1
}
};
es equivalente a:
// Only the *getters* for Collection and Property are called
var foo = new Foo();
foo.Collection.Add(1);
foo.Property.Value = 1;
Compara eso con:
var foo = new Foo
{
Collection = new List<int> { 1 },
Property = new Bar { Value = 1 }
};
que es equivalente a:
// The setters for Collection and Property are called
var foo = new Foo();
foo.Collection = new List<int> { 1 };
foo.Property = new Bar { Value = 1 };