.Net的LINQ中的错误,还是我遗漏了什么?

时间:2012-03-22 10:39:34

标签: c# .net linq

我有一个奇怪的错误,我不明白,并改变LINQ的IEnumerable列表中途修复它,我不明白为什么

不是真正的代码,但非常相似 以下代码不起作用:

// an IEnumerable of some object (Clasess) internally an array
var ansestors = GetAnsestors();

            var current = GetCurrentServerNode();

            var result = from serverNode in ansestors
                         select new PolicyResult
                                    {
                                      //Some irrelevant stuff 
                                        OnNotAvailableNode = NodeProcessingActionEnum.ContinueExecution,
                                    };

            var thisNode = new PolicyResult
            {
                //Some irrelevant stuff 
                OnNotAvailableNode = NodeProcessingActionEnum.ThrowException,
            };

            result = result.Reverse();
            result = result.Concat(new List<PolicyResult> { thisNode });

            result.First().OnNotAvailableNode = NodeProcessingActionEnum.ThrowException;

            // When looking in the debugger, and in logs, the first element of the
            // result sequence has OnNotAvailableNode set to ContinueExecution
            // Which doesnt make any sense...

但是当我将结尾更改为以下内容时,它会起作用:

        result = result.Reverse();
        result = result.Concat(new List<PolicyResult> { thisNode });

        var policyResults = result.ToList();
        var firstPolicyResult = policyResults.First();

        firstPolicyResult.OnNotAvailableNode = NodeProcessingActionEnum.ThrowException;
        return policyResults;

这里的所有类型都是类(引用类型),但NodeProcessingActionEnum是一个枚举。

这是一个错误吗?

我错过了一些关于LINQ的重要内容?

帮助?

2 个答案:

答案 0 :(得分:5)

result.First()执行(延迟/延迟)查询。

该行将设置值OK,但是当您稍后使用result时,将再次执行 查询。

稍后您正在查看新获取的副本。事实上它是不同的让我假设GetAnsestors()也被懒惰地评估并且不在内存中List<>

这意味着ToList()值得进行优化以及修复。请注意,在ToList之后,您还可以使用

 var firstPolicyResult = policyResults[0];  

答案 1 :(得分:0)

问题是在IEnumerable上运行First会将其从枚举器中删除,因此您必须检查下一个元素。其实我已经改变了主意 - 这可能不是它。不过,这个解决方案可能值得一试。

您可以使用能够为您进行更改的内容包装IEnumerable,例如使用the Select override which accepts an index too

var modifiedResults = results.Select((r, index) => {
    if (index == 0) {
        // This is the first element
        r.OnNotAvailableNode = NodeProcessingActionEnum.ThrowException;
    }
    return r;
});

(未经测试)应该做到这一点。