当我发现一些我不完全理解的东西时,我正在处理一些代码,因此我创建了以下测试代码:
static void Main(string[] args)
{
string myKey = "bla";
var list = new List<KeyValuePair<string, string>>();
var list2 = new List<Test>();
var bla1 = (from a in list where a.Key == myKey select a.Value).FirstOrDefault();
var bla2 = list.FirstOrDefault(x => x.Key == myKey).Value;
var bla3 = (from a in list2 where a.Key == myKey select a.Value).FirstOrDefault();
var bla4 = list2.FirstOrDefault(x => x.Key == myKey).Value;
}
struct Test
{
public string Key { get; set; }
public string Value { get; set; }
public Test(string key, string value)
{
Key = key;
Value = value;
}
}
现在,只要Test是一个结构,所有4个bla-line都能正常工作。但是,只要我将Test
更改为class
而不是struct
,bla4就会失败。怎么会这样?不是bla4只是另一种(lambda)做bla3的方式,因此应该表现相同吗?为什么列表包含struct's
或classes
会有所不同?有没有办法让一个lambda版本的bla4不会抛出异常,而是像其他人一样返回null?
答案 0 :(得分:1)
结构永远不能是null
。
因此,您对FirstOrDefault()
的调用实际上会导致构建新的结构,因为default(struct)
实际上是new(struct)
。
但是,如果您将其更改为某个班级,则default(class)
为null
。
这是你的电话结果
list2.FirstOrDefault(x => x.Key == myKey)
实际上会导致null
一旦被归类,就会被返回。因此,在尝试访问.Value
时,您应该收到 NullReferenceException 。
在外行人看来,你的bla3实际上做的是检查集合中是否有匹配的项目。如果有,它将选择该项目的属性Value
,否则它将返回该属性的默认类型。
您的bla4会查找是否找到与Key
属性匹配的项目。如果是,则选择第一个项目,如果不是,则创建该项目类型的默认值并返回该项目。然后,您尝试访问该返回值的Value
属性。
答案 1 :(得分:1)
类类型的默认值为null。 struct的默认值是一个空结构。这就是FirstOrDefault(..).Value
因NullReferenceException而失败的原因。
在尝试访问结果之前,您应该检查FirstOrDefault()
是否确实返回了某些内容。
var item = list2.FirstOrDefault(x => x.Key == myKey);
var bla4 = (item == null)?null:item.Value;
在C#6及更高版本中,您可以使用?.
运算符执行相同的检查:
var item = list2.FirstOrDefault(x => x.Key == myKey)?.Value;
另一种选择是使用??
将null替换为默认值。
var item = list2.FirstOrDefault(x => x.Key == myKey) ?? new Test();
var bla4 = item.Value;
在这种情况下创建一个特殊的Empty
对象是很常见的,例如:
class Test
{
//...
public static readonly Empty =new Test();
}
var item = list2.FirstOrDefault(x => x.Key == myKey) ?? Test.Empty;
var bla4 = item.Value;
答案 2 :(得分:1)
bla4不是另一种(lambda)做bla3的方式,因此应该表现相同吗?
没有。 bla3
从列表中包含的对象中提取一些字符串。然后,您在该组字符串上调用FirstOrDefault
并获取null
值,因为该集合为空。
bla4
直接在对象集上调用FirstOrDefault
,然后然后从默认对象中获取字符串属性Value
。
当列表中包含的对象是结构体时,默认值将包含null
Value
属性。这就是为什么他们表面看起来很相似。但要非常清楚 - 正在调用Value
并且FirstOrDefault
被调用的顺序不同,而FirstOrDefault
正在对不同类型的事物进行操作。
当然,bla2
与bla1
完全相同。