无法将null赋给array类型的匿名属性
我有任何具有( Hanger
)属性的( Pilot
)对象数组,它可以为null,它本身具有( List
)属性。 出于测试目的,我想简化并将其“展平”为具有属性PilotName
(字符串)和Planes
(数组)的匿名对象,但不确定如何处理空的Hanger
属性或空的PlanesList
。
(为什么是匿名对象?因为我正在测试的API的对象是只读的,我希望测试是’声明性的’:自包含,简单易读……但我对其他建议持开放态度。我也是我试图了解有关LINQ的更多信息。)
例
class Pilot { public string Name; public Hanger Hanger; } class Hanger { public string Name; public List 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() { 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)); }
直接的问题是expected... Planes = null
的行expected... Planes = null
错误,
无法分配给匿名类型属性,但承认底层问题可能是在
actual
中使用null
使用null
并不是最好的方法。
任何想法如何在expected
分配空数组或采取与actual
null
不同的方法?
发生了两件事:
首先,当您使用new { Name = Value}
构造匿名类型的实例时,为了构建类型,编译器需要能够计算出Value
的类型 。 只有null
本身没有类型,因此编译器不知道给Planes
成员提供什么类型。
现在,如果你使用命名类型作为值,你可以说(type)null
并完成,但是因为你想要一个另一个匿名类型的数组,没有办法引用它(它是匿名的!)。
那么如何将null
类型作为匿名类型的数组? 好吧,C#规范保证了具有相同名称和类型(以相同顺序!)的成员的匿名类型是统一的 ; 也就是说,如果我们说
var a = new { Foo = "Bar" }; var b = new { Foo = "Baz" };
然后a
和b
具有相同的类型 。 我们可以使用这个事实来得到我们的适当类型的null
:
var array = (new[] { new { PlaneName = "" } }); array = null;
它不漂亮,但它的工作原理 – 现在array
有正确的类型,但null
值 。 所以这个编译:
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" } } } };
您必须使用类型化的 null :
(List)null
要么
(Plane[])null
否则,编译器不知道您希望匿名类型的成员是什么类型。
更新正如@AakashM正确指出的那样 – 这解决了为匿名成员分配null
问题 – 但实际上并没有编译 – 如果确实如此,它将不允许您引用这些成员。
修复就是这样做(不幸的是, null
和匿名Planes
数组都需要转换:
var expected = new[] { new { PilotName = "Higgins", Planes = (IEnumerable)null }, new { PilotName = "Higgins", Planes = (IEnumerable)new [] { new { PlaneName = "B-52" }, new { PlaneName = "F-14" } } } };
因此,使用IEnumerable
作为成员类型。 您也可以使用IEnumerable
但效果将是相同的。
或者 – 你可以使用IEnumerable
作为常见类型 – 这可以让你这样做:
Assert.AreEqual("B-52", expected[1].Planes.First().PlaneName);
只需使用default(Plane[])
而不是null
。