C# 无法将 null 分配给数组类型的匿名属性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14317161/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 11:24:54  来源:igfitidea点击:

Cannot assign null to anonymous property of type array

c#linqanonymous-types

提问by petemoloy

I have any array of (Pilot) objects with a (Hanger) property, which may be null, which itself has a (List<Plane>) property. For testing purposes, I want to simplify and 'flatten' this to an anonymous object with properties PilotName(string) and Planes(array) but not sure how to handle a null Hangerproperty or an empty PlanesList.

我有任何Pilot具有 ( Hanger) 属性的 ( ) 对象数组,它可能为 null,它本身具有 ( List<Plane>) 属性。出于测试目的,我想将其简化并“扁平化”为具有属性PilotName(字符串)和Planes(数组)的匿名对象,但不确定如何处理 nullHanger属性或空的PlanesList.

(Why anonymous objects? Because the objects of the API I'm testing are read only and I want the test to be 'declarative': self contained, simple and readable... but I'm open to other suggestions. Also I'm trying to learn more about LINQ.)

(为什么是匿名对象?因为我正在测试的 API 的对象是只读的,我希望测试是“声明性的”:自包含、简单和可读......但我愿意接受其他建议。我也是我正在尝试了解有关 LINQ 的更多信息。)

example

例子

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));
    }

The immediate problem is that the line expected... Planes = nullerrors with,

直接的问题是线路expected... Planes = null错误,

Cannot assign to anonymous type property but admit the underlying problem may be that using nullin actualis using nullis not the best approach in the first place.

不能分配给匿名类型属性,但承认潜在的问题可能是 using nullin actualis usingnull不是最好的方法。

Any ideas how to either assign the null array in expectedor take a different approach than nullin actual?

任何想法如何分配空数组 inexpected或采用与nullin不同的方法actual

采纳答案by AakashM

There are two things happening:

有两件事发生:

Firstly, when you construct an instance of an anonymous type using new { Name = Value}, in order to build the type the compiler needs to be able to work out the typeof Value. Just nullon its own doesn't have a type, so the compiler wouldn't know what type to give your Planesmember.

首先,当你构建使用匿名类型的实例new { Name = Value},以建设编译器需要能够制定出类型类型Value。就null其本身而言没有类型,因此编译器不知道该给您的Planes成员什么类型。

Now, if you were using a named type for the value, you could just say (type)nulland be done, BUT because you want an array of another anonymous type, there's no way to referto is (it's anonymous!).

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

So how do you get nulltyped as array of an anonymous type? Well, the C# spec guarantees that anonymous types with members the same names and types (in the same order!) are unified; that is, if we say

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

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

then aand bhave the same type. We can use this fact to get our suitably-typed nullthus:

然后ab具有相同的类型。我们可以使用这个事实来获得我们的适当类型null

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

It's not pretty but it works - now arrayhas the right typebut a nullvalue. So this compiles:

它不漂亮但它有效 - 现在array有正确的type但一个nullvalue。所以这编译:

        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" }
                                                    }
                                   }
                           };

回答by Andras Zoltan

You have to use a typednull:

您必须使用类型化的null

(List<Plane>)null

Or

或者

(Plane[])null

Otherwise the compiler has no idea what type you want the anonymous type's member to be.

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

UpdateAs @AakashM has rightly pointed out - this solves your problem of assigning a nullto an anonymous member - but doesn't actually compile - and if it did it wouldn't allow you to refer to these members.

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

A fix would be to do this (unfortunately both the nulland the anonymous Planesarray will need casting:

解决方法是这样做(不幸的是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" } 
                          }
      }
};

So use IEnumerableas the member type. You could also use IEnumerable<object>but the effect will be the same either way.

所以IEnumerable用作成员类型。您也可以使用,IEnumerable<object>但无论哪种方式,效果都是一样的。

Or - you could use IEnumerable<dynamic>as the common type - this would let you do this:

或者 - 您可以将其IEnumerable<dynamic>用作通用类型 - 这将让您执行以下操作:

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

回答by Viacheslav Ivanov

Just use default(Plane[])instead of null.

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