不能将数组类型的匿名属性赋值为null

本文关键字:属性 赋值 null 数组 类型 不能 | 更新日期: 2023-09-27 17:52:45

我有任何具有(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不同的方法?

不能将数组类型的匿名属性赋值为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" };

ab具有相同类型的。我们可以使用这个事实来获得合适类型的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