使用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);
编译器是否认识到分组需要该值并将其保留?
不,因为getProperty
可能有预期的副作用。
如果没有,那么必须有一种方法来选择匿名类型,并根据该类型查询Where和GroupBy语句。是否可以使用匿名类型执行此操作?
是的。只需将new fileSelector() {...}
替换为new {...}
,代码就可以正常工作。不过,请注意,在您的代码中(以及在使用匿名类型的修改版本中),分组的元素是fileSelector和匿名类型,而不是myFile。请参阅Scott Chamberlain的解决方案,了解如何解决此问题。
或者,您可以使用let
子句来存储中间值:
var groups = from file in files
let prop = file.getProperty(propName)
where !string.IsNullOrWhiteSpace(prop)
group file by prop;
编译器是否认识到分组需要该值并将其保留?
不,它会碰到两次数值。
实际上,与最后的示例非常接近,您可以使用annonamous类型,只需为匿名类型的每个成员提供名称,然后添加一个元素选择器,使分组的主体成为file
属性。
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);