无法将null分配给array类型的匿名属性

时间:2013-01-14 10:57:06

标签: c# linq anonymous-types

我有任何具有(Pilot)属性的(Hanger)对象数组,该属性可以为null,它本身具有(List<Plane>)属性。出于测试目的,我想简化并将其“展平”为具有属性PilotName(字符串)和Planes(数组)的匿名对象,但不确定如何处理null 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行错误,

  

无法分配给匿名类型的属性,但承认潜在的问题可能是null使用actual使用null并不是最好的方法。

如何在expected中分配空数组或采用与null中的actual不同的方法?

3 个答案:

答案 0 :(得分:45)

您必须使用 键入 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);

答案 1 :(得分:35)

发生了两件事:

首先,当您使用new { Name = Value}构造匿名类型的实例时,为了构建类型,编译器需要能够计算{{1}的类型 }。仅Value本身没有类型,因此编译器不知道为null成员提供什么类型。

现在,如果你使用命名类型作为值,你可以说Planes并完成,但是因为你想要一个另一个匿名类型的数组,没有办法引用 to is(这是匿名的!)。

那么如何将(type)null作为匿名类型的数组输入?好吧,C#规范保证匿名类型的成员具有相同的名称和类型(以相同的顺序!)统一;也就是说,如果我们说

null

然后var a = new { Foo = "Bar" }; var b = new { Foo = "Baz" }; a 相同类型。我们可以使用这个事实来得到我们适当类型的b因此:

null

它不漂亮但它有效 - 现在var array = (new[] { new { PlaneName = "" } }); array = null; 具有正确的类型,但array 。所以这个编译:

null

答案 2 :(得分:8)

只需使用default(Plane[])代替null