使用LINQ进行结构与类

时间:2017-04-13 09:07:57

标签: c# linq class struct

当我发现一些我不完全理解的东西时,我正在处理一些代码,因此我创建了以下测试代码:

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'sclasses会有所不同?有没有办法让一个lambda版本的bla4不会抛出异常,而是像其他人一样返回null?

3 个答案:

答案 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正在对不同类型的事物进行操作。

当然,bla2bla1完全相同。