关于c#:无法为类型为array的匿名属性赋值null

Cannot assign null to anonymous property of type array

我有一个(Pilot对象数组,它有一个(Hanger属性,可以是空的,它本身有一个(List属性。为了测试的目的,我想将其简化并"扁平化"为一个具有属性PilotNamePlanes的匿名对象,但不确定如何处理空的Hanger属性或空的PlanesList

(为什么是匿名对象?因为我测试的API对象是只读的,我希望测试是"声明性的":自包含的、简单的和可读的…但我愿意接受其他建议。另外,我还想了解更多关于Linq的信息。)

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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的错误是,

Cannot assign to anonymous type property but admit the underlying problem may be that using null in actual is using null is not the best approach in the first place.

对于如何在expected中分配空数组,或者采用与actual中的null不同的方法,有什么想法吗?


必须使用键入的空值:

1
(List<Plane>)null

1
(Plane[])null

否则,编译器不知道您希望匿名类型的成员是什么类型。

更新正如@aakashm正确指出的那样-这解决了将null分配给匿名成员的问题-但实际上并没有编译-如果这样做,就不允许您引用这些成员。

解决方法是这样做(不幸的是,null和匿名Planes数组都需要强制转换:

1
2
3
4
5
6
7
8
9
10
11
12
13
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作为通用类型-这样可以做到:

1
Assert.AreEqual("B-52", expected[1].Planes.First().PlaneName);


有两件事发生了:

首先,当使用new { Name = Value}构造匿名类型的实例时,为了构建该类型,编译器需要能够计算出Value的类型。只是null本身没有类型,所以编译器不知道要给Planes成员什么类型。

现在,如果您正在使用一个命名类型作为值,您可以只说(type)null并完成,但是因为您需要另一个匿名类型的数组,所以没有办法引用is(它是匿名的!).

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

1
2
var a = new { Foo ="Bar" };
var b = new { Foo ="Baz" };

那么,ab有相同的类型。我们可以利用这一事实得到我们的适当类型的null,因此:

1
2
var array = (new[] { new { PlaneName ="" } });
array = null;

它不是很漂亮,但很管用——现在array有了正确的类型,但null的值。因此,这是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
        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