Linq避免两次调用函数

时间:2016-07-20 18:42:42

标签: c# linq anonymous-types

使用Linq to Objects查询可能需要根据函数的结果进行过滤并返回该函数的值。

例如

files.Where(x => string.IsNullOrWhiteSpace(x.getProperty(propName)))
                .GroupBy(x => x.getProperty(propName));

编译器是否认识到分组所需的值并保留它?

如果它没有那么必须有一种方法来选择匿名类型并查询Where和GroupBy语句。是否可以使用匿名类型执行此操作?

我可以声明一个类并使用它。

class fileSelector
{
    internal string prop;
    internal myFile file;
}

var groups = files
     .Select(x => new fileSelector() { prop = x.getProperty(propName),  file = x })
     .Where(x => !string.IsNullOrWhiteSpace(x.prop))
     .GroupBy(x => x.prop);

但有没有办法用匿名类型做到这一点?

这是我尝试匿名类型

var groups = files.Select(x => new { x.getProperty(propName),  x })
                  .Where(x => !string.IsNullOrWhiteSpace(x.prop))
                  .GroupBy(x => x.prop);

但这会产生错误

无效的匿名类型成员声明符。必须使用成员分配,简单名称或成员访问声明匿名类型成员。

最终答案

var groups = files
     .Select(x => new { prop = x.getProperty(propName),  file = x })
     .Where(x => !string.IsNullOrWhiteSpace(x.prop))
     .GroupBy(x => x.prop, x => x.file);

2 个答案:

答案 0 :(得分:4)

  

编译器是否认识到分组所需的值并保留它?

不,因为getProperty可能会产生预期的副作用。

  

如果它没有那么必须有一种方法来选择匿名类型并查询Where和GroupBy语句。是否可以使用匿名类型执行此操作?

是。只需将new fileSelector() {...}替换为new {...},您的代码就可以按原样运行。但请注意,在您的代码中(以及使用匿名类型的修改版本),分组的元素是fileSelector和匿名类型,而不是myFile。有关如何解决此问题,请参阅Scott Chamberlain's solution

或者,您可以使用the let clause来存储中间值:

var groups = from file in files
             let prop = file.getProperty(propName)
             where !string.IsNullOrWhiteSpace(prop)
             group file by prop;

答案 1 :(得分:1)

  

编译器是否认识到分组所需的值并保留它?

不,它会触摸两次值。

你真正与你的最后一个例子非常接近,你可以使用一个annonamous类型,只需为匿名类型的每个成员命名,然后添加一个元素选择器,使分组的主体{{1属性。

file