2016-06-08 138 views
1

我一直在试图重写LINQ中的一些命令式代码,直到我意识到我错过了什么。但我不知道为什么这是一个问题。考虑以下。测试失败运行Test.Test2(testList)linq过滤器在默认情况下不能出现?

序列中没有匹配的元素

在过去,我曾治疗过这些形式可以互换,通过推我的谓词的FirstSingle等编写代码较小..条款。很明显,当涉及DeafultIfEmpty时,我不能这么做。这是因为使用WhereFirst,Single等是不可互换的吗?或者,是因为DefaultIfEmpty条款引入了复杂性?

编辑1 我添加了一个测试,显示FirstOrDefault不起作用。它失败,“未找到”不等于(空)。

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

回答

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

+0

这对我来说很有意义,我没有考虑过操作顺序的重要性......并且我认为DefaultIfEmpty为后面的操作员设置了一个默认值,如果它们什么都不返回的话。它的行为如你所描述的那样。 – cocogorilla

1

你应该使用FirstOrDefault(),这样当阵列没有任何匹配,则返回默认值,而不是抛出异常。


编辑:

Test1,所述Where子句后,所得到的序列变空。当应用DefaultIfEmpty时,结果序列将包含单个元素"not found"

Test2中,当应用DefaultIfEmpty时,该序列尚未过滤。因此,传递相同的序列。但是,First(predicate)试图减少序列时,没有什么可以出来,这就是为什么InvalidOperationException发生。

+0

这并不值得。当我使用first或default的时候,我的“DefaultIfEmpty”被忽略,函数返回null。 – cocogorilla

+0

@cocogorilla查看我的编辑 – Xiaoy312

0

我同意Xiaoy312。 FirstOrDefault方法更好。然后检查它是否为null。

public static string Test2(params string[] input) 
{ 
    return input.FirstOrDefault(x => x == "apples") 
} 
+0

这个问题不是什么架构会更好......这个例子是人为设计的。问题是关于DefaultIfEmpty如何工作。雅各布的答案是胜利的,因为他指出了“订单问题”,这是我不明白的。 – cocogorilla