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