我有任何具有(Hanger
)属性的(Pilot
)对象数组,该数组可能为null,其本身具有(List<Plane>
)属性。出于测试目的,我想将其简化并"扁平化"为具有属性PilotName
(字符串)和Planes
(数组)的匿名对象,但不确定如何处理空Hanger
属性或空PlanesList
。
(为什么是匿名对象?因为我正在测试的API对象是只读的,我希望测试是"声明性的":自包含的,简单的和可读的……但我愿意接受其他建议。我也在努力学习更多关于LINQ的知识。
例子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));
}
直接的问题是expected... Planes = null
行出错了,
不能赋值给匿名类型属性,但承认潜在的问题可能是,在
actual
中使用null
是在使用null
,这首先不是最好的方法。
是否知道如何在expected
中分配null数组或在actual
中采用与null
不同的方法?
你必须使用一个输入空:
(List<Plane>)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<object>
,但效果都是一样的。
或者-您可以使用IEnumerable<dynamic>
作为通用类型-这将允许您这样做:
Assert.AreEqual("B-52", expected[1].Planes.First().PlaneName);
发生了两件事:
首先,当使用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"
}
}
}
};
用default(Plane[])
代替null
。