我一直在努力在LINQ中重写一些命令式代码,直到我意识到自己缺少了什么。但我不知道为什么这是一个问题。考虑以下。测试无法使用
运行Test.Test2(testList)
序列不包含匹配元素
过去,我对这些表单进行了交替处理,通过将我的谓词推送到First
,Single
等语句来编写更小的代码。显然,当涉及DeafultIfEmpty
时,我不能这样做。这是因为使用Where
和First
,Single
等不可互换?或者,是因为DefaultIfEmpty
子句引入了并发症吗?
编辑1 我添加了一个测试,表明FirstOrDefault不起作用。它失败了"未找到"不等于(null)。
public static class Test
{
public static string Test1(params string[] input)
{
return input
.Where(x => x == "apples")
.DefaultIfEmpty("bannanas")
.First();
}
public static string Test2(params string[] input)
{
return input
.DefaultIfEmpty("bannanas")
.First(x => x == "apples");
}
public static string Test3(params string[] input)
{
return input
.DefaultIfEmpty("bannanas")
.FirstOrDefault(x => x == "apples");
}
}
public class TestStuff
{
[Fact]
public static void TestOneAndTwo()
{
var testList = new string[] { "oranges", "pears", "pineapples" };
var one = Test.Test1(testList);
var two = Test.Test2(testList);
Assert.Equal(one, two);
}
[Fact]
public static void TestOneAndThree()
{
var testList = new string[] { "oranges", "pears", "pineapples" };
var one = Test.Test1(testList);
var three = Test.Test3(testList);
Assert.Equal(one, three);
}
}
答案 0 :(得分:2)
LINQ方法的顺序很重要,请考虑每个方法对输入可枚举({ "oranges", "pears", "pineapples" }
)的作用:
public static string Test1(params string[] input)
{
return input
.Where(x => x == "apples") // empty enumerable, because no item matches "apples"
.DefaultIfEmpty("not found") // {"not found"}, since the enumerable is empty
.First(); //"not found", since we have this item
}
public static string Test2(params string[] input)
{
return input
.DefaultIfEmpty("not found") // { "oranges", "pears", "pineapples" }
//i.e., nothing changes, because input is not empty
.First(x => x == "apples"); //Exception because there is no
//item that is equal to "apples"
}
如果您将最后一种方法从First
更改为FirstOrDefault
,则会生成null
,因为default(string)
为null
。
答案 1 :(得分:1)
你应该使用FirstOrDefault()
,这样当数组没有任何匹配时,会返回一个默认值,而不是抛出异常。
编辑:
在Test1
中,在Where
子句之后,结果序列变为空。应用DefaultIfEmpty
后,生成的序列将包含单个元素"not found"
。
在Test2
中,当应用DefaultIfEmpty
时,序列尚未过滤。因此,传递相同的序列。但是,当First(predicate)
尝试减少序列时,没有任何内容可以出现,这就是InvalidOperationException
发生的原因。
答案 2 :(得分:0)
我同意Xiaoy312。 FirstOrDefault方法更好。然后检查一下它是否为空。
public static string Test2(params string[] input)
{
return input.FirstOrDefault(x => x == "apples")
}