c# - valores - No se puede asignar null a la propiedad anónima de tipo array
verificar null c# (3)
Tengo cualquier conjunto de objetos ( Pilot
) con una propiedad ( Hanger
), que puede ser nula, que a su vez tiene una propiedad ( List<Plane>
). Para propósitos de prueba, quiero simplificar y ''aplanar'' esto a un objeto anónimo con las propiedades PilotName
(cadena) y Planes
(matriz) pero no estoy seguro de cómo manejar una propiedad de Hanger
nula o una lista de PlanesList
vacía.
(¿Por qué objetos anónimos? Porque los objetos de la API que estoy probando son de solo lectura y quiero que la prueba sea ''declarativa'': autocontenida, simple y legible ... pero estoy abierto a otras sugerencias. También estoy '' Estoy tratando de aprender más sobre LINQ.
ejemplo
class Pilot
{
public string Name;
public Hanger Hanger;
}
class Hanger
{
public string Name;
public List<Plane> PlaneList;
}
class Plane
{
public string Name;
}
[TestFixture]
class General
{
[Test]
public void Test()
{
var pilots = new Pilot[]
{
new Pilot() { Name = "Higgins" },
new Pilot()
{
Name = "Jones", Hanger = new Hanger()
{
Name = "Area 51",
PlaneList = new List<Plane>()
{
new Plane { Name = "B-52" },
new Plane { Name = "F-14" }
}
}
}
};
var actual = pilots.Select(p => new
{
PilotName = p.Name,
Planes = (p.Hanger == null || p.Hanger.PlaneList.Count == 0) ? null : p.Hanger.PlaneList.Select(h => ne
{
PlaneName = h.Name
}).ToArray()
}).ToArray();
var expected = new[] {
new { PilotName = "Higgins", Planes = null },
new
{
PilotName = "Jones",
Planes = new[] {
new { PlaneName = "B-52" },
new { PlaneName = "F-14" }
}
}
};
Assert.That(actual, Is.EqualTo(expected));
}
El problema inmediato es que la línea expected... Planes = null
errores expected... Planes = null
con,
No se puede asignar a una propiedad de tipo anónimo, pero admitir que el problema subyacente puede ser que usar
null
enactual
es usarnull
no es el mejor enfoque en primer lugar.
¿Alguna idea de cómo asignar la matriz nula en expected
o adoptar un enfoque diferente al null
en actual
?
Hay dos cosas que suceden:
En primer lugar, cuando construye una instancia de un tipo anónimo utilizando el new { Name = Value}
, para construir el tipo que necesita el compilador para poder calcular el tipo de Value
. Solo el null
por sí solo no tiene un tipo, por lo que el compilador no sabría qué tipo dar a su miembro Planes
.
Ahora, si estuviera usando un tipo con nombre para el valor, simplemente podría decir (type)null
y terminar, PERO porque desea una matriz de otro tipo anónimo, no hay manera de referirse a (¡es anónimo!).
Entonces, ¿cómo se escribe null
como una matriz de un tipo anónimo? Bueno, la especificación de C # garantiza que los tipos anónimos con miembros con los mismos nombres y tipos (¡en el mismo orden!) Están unificados ; es decir, si decimos
var a = new { Foo = "Bar" };
var b = new { Foo = "Baz" };
entonces b
tienen el mismo tipo . Podemos usar este hecho para obtener nuestro null
adecuadamente tipeado así:
var array = (new[] { new { PlaneName = "" } });
array = null;
No es bonito pero funciona; ahora array
tiene el tipo correcto pero un valor null
. Así que esto compila:
var array = new[] { new { PlaneName = "" } };
array = null;
var expected = new[]
{
new
{
PilotName = "Higgins",
Planes = array
},
new
{
PilotName = "Higgins",
Planes = new[]
{
new { PlaneName = "B-52" },
new { PlaneName = "F-14" }
}
}
};
Simplemente use el default(Plane[])
lugar de null
.
Tienes que usar un nulo mecanografiado :
(List<Plane>)null
O
(Plane[])null
De lo contrario, el compilador no tiene idea de qué tipo quiere que sea el miembro del tipo anónimo.
Actualizar Como @AakashM ha señalado correctamente: esto resuelve su problema de asignar un null
a un miembro anónimo, pero en realidad no se compila, y si lo hiciera, no le permitiría referirse a estos miembros.
Una solución sería hacer esto (desafortunadamente, tanto la matriz de Planes
anónima como la null
necesitarán ser lanzadas:
var expected = new[] {
new {
PilotName = "Higgins",
Planes = (IEnumerable)null
},
new {
PilotName = "Higgins",
Planes = (IEnumerable)new [] {
new { PlaneName = "B-52" },
new { PlaneName = "F-14" }
}
}
};
Así que usa IEnumerable
como el tipo de miembro. También puede usar IEnumerable<object>
pero el efecto será el mismo de cualquier manera.
O, podría usar IEnumerable<dynamic>
como el tipo común, esto le permitiría hacer esto:
Assert.AreEqual("B-52", expected[1].Planes.First().PlaneName);