TLDR: Este es un error conocido de larga data. Primero escribí sobre esto en 2010:
https://blogs.msdn.microsoft.com/ericlippert/2010/01/18/a-definite-assignment-anomaly/
Es inofensivo y puede ignorarlo con seguridad, y felicitarse por encontrar un error algo oscuro.
¿Por qué el compilador no impone que Email
debe asignarse definitivamente?
Oh, lo hace, de una manera. Simplemente tiene una idea errónea de qué condición implica que la variable está definitivamente asignada, como veremos.
¿Por qué este código se compila si la estructura se crea en un ensamblaje separado, pero no se compila si la estructura se define en el ensamblaje existente?
Ese es el quid de la falla. El error es una consecuencia de la intersección de cómo el compilador de C # realiza una verificación de asignación definitiva en las estructuras y cómo el compilador carga los metadatos de las bibliotecas.
Considera esto:
struct Foo
{
public int x;
public int y;
}
// Yes, public fields are bad, but this is just
// to illustrate the situation.
void M(out Foo f)
{
OK, en este punto, ¿qué sabemos? f
es un alias para una variable de tipo Foo
, por lo que el almacenamiento ya se ha asignado y definitivamente está al menos en el estado en que salió del asignador de almacenamiento. Si la persona que llama colocó un valor en la variable, ese valor está allí.
¿Qué requerimos? Requerimos que f
se asigne definitivamente en cualquier punto donde el control salga M
normalmente. Entonces esperarías algo como:
void M(out Foo f)
{
f = new Foo();
}
que establece f.x
y f.y
a sus valores predeterminados. ¿Pero qué hay de esto?
void M(out Foo f)
{
f = new Foo();
f.x = 123;
f.y = 456;
}
Eso también debería estar bien. Pero, y aquí está el truco, ¿por qué necesitamos asignar los valores predeterminados solo para eliminarlos un momento después? ¡El comprobador de asignación definitiva de C # verifica si cada campo está asignado! Esto es legal:
void M(out Foo f)
{
f.x = 123;
f.y = 456;
}
¿Y por qué eso no debería ser legal? Es un tipo de valor. f
es una variable y ya contiene un valor de tipo válido Foo
, así que configuremos los campos y listo, ¿verdad?
Derecha. Entonces, ¿cuál es el error?
El error que ha descubierto es: como ahorro de costos, el compilador de C # no carga los metadatos de los campos privados de estructuras que se encuentran en las bibliotecas a las que se hace referencia . Esos metadatos pueden ser enormes y ralentizaría el compilador para ganar muy poco para cargarlo todo en la memoria cada vez.
Y ahora debería poder deducir la causa del error que ha encontrado. Cuando el compilador verifica si el parámetro out está definitivamente asignado, compara el número de campos conocidos con el número de campos que se inicializaron definitivamente y, en su caso, solo conoce los cero campos públicos porque los metadatos del campo privado no se cargaron. . El compilador concluye "cero campos requeridos, cero campos inicializados, estamos bien".
Como dije, este error ha existido por más de una década y la gente como usted ocasionalmente lo redescubre y lo informa. Es inofensivo y es poco probable que se solucione porque solucionarlo es de beneficio casi nulo pero tiene un alto costo de rendimiento.
Y, por supuesto, el error no reproduce los campos privados de estructuras que están en el código fuente de su proyecto, porque obviamente el compilador ya tiene información sobre los campos privados disponibles.
struct Dog{}
, todo está bien.