Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 无法将null分配给array类型的匿名属性_C#_Linq_Anonymous Types - Fatal编程技术网

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

C# 无法将null分配给array类型的匿名属性,c#,linq,anonymous-types,C#,Linq,Anonymous Types,我有任何带有(Hanger)属性的(Pilot)对象数组,该属性可能为空,其本身具有(List)属性。出于测试目的,我想将其简化并“展平”为具有属性PilotName(字符串)和Planes(数组)的匿名对象,但不确定如何处理空Hanger属性或空PlanesList (为什么是匿名对象?因为我正在测试的API的对象是只读的,我希望测试是“声明性的”:自包含的、简单的和可读的……但我愿意接受其他建议。我还试图了解更多关于LINQ的信息。) 范例 class Pilot { public

我有任何带有(
Hanger
)属性的(
Pilot
)对象数组,该属性可能为空,其本身具有(
List
)属性。出于测试目的,我想将其简化并“展平”为具有属性
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));
    }
class-Pilot
{
公共字符串名称;
公共吊架;
}
班级挂钩
{
公共字符串名称;
公开名单;
}
类平面
{
公共字符串名称;
}
[测试夹具]
普通班
{
[测试]
公开无效测试()
{
var导频=新导频[]
{
new Pilot(){Name=“Higgins”},
新飞行员()
{
Name=“Jones”,吊架=新吊架()
{
Name=“第51区”,
PlaneList=新列表()
{
新平面{Name=“B-52”},
新平面{Name=“F-14”}
}
}
}
};
var实际值=导频。选择(p=>new
{
PilotName=p.名称,
平面=(p.Hanger==null | | p.Hanger.PlaneList.Count==0)?null:p.Hanger.PlaneList.Select(h=>ne)
{
PlaneName=h.名称
}).ToArray()
}).ToArray();
预期风险值=新[]{
新的{PilotName=“Higgins”,Planes=null},
新的
{
PilotName=“琼斯”,
平面=新[]{
新的{PlaneName=“B-52”},
新建{PlaneName=“F-14”}
}
}
};
断言(实际的,等于(预期的));
}
直接的问题是行
预期的…Planes=null
错误

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

如何在
预期的
中分配空数组,或者采取与
实际的
中的
null
不同的方法

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

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

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

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
作为通用类型-这将允许您执行以下操作:

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

只需使用
default(Plane[])
而不是
null

就可以了,发生了两件事:

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

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

那么,如何将
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" }
                                                    }
                                   }
                           };

…但现在,由于OP希望该类型是另一个匿名类型的数组,因此无法引用它。啊,这是一个好观点。
IEnumerable
可能会这样做,但它确实会消除任何编译时类型知识。是的,切换到
IEnumerable
会起作用-但我们可以修复测试代码,而无需更改正在测试的代码ted;看看我的答案。好主意!为了完整性,谢谢你和安德拉:
null作为平面[]
也可以。这很好(如果有点奇怪的话!)-我以前读过这方面的文章,但从来没有发现它的用途。另一种方法是内联
new[]{new{PlaneName=”“}。Take(0)。ToArray()
更新示例的主要问题是,您正在检查枚举数(由
导频创建的
Where selectArrayInterator
)和数组之间的相等性。您可以使用
ToArray()在<代码>的结尾处,子句将它强制成数组。对于更广泛的问题,我会说两件事:首先,要考虑的一个非常好的变化是:当没有任何项目时,
Planes
应该是一个空集合,而不是
null
。这样更容易处理;。其次,我怀疑您必须对实际和预期之间的相等性进行更“智能”的检查;即
var array = (new[] { new { PlaneName = "" } });
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" }
                                                    }
                                   }
                           };