我经常在linq中尝试创建一个对象并为其添加属性而感到沮丧。
的例子:
var blgFiles = Directory.GetFiles( rootFolder, "*.blg", SearchOption.AllDirectories );
var data = blgFiles.Select( file => new
{
BLGFile = file,
CSVFile = Path.ChangeExtension( file, "csv" ),
CSVFileExists = File.Exists( CSVFile )
} );
无法编译,因为我无法在File.Exists中使用CSVFile .
我可以这样做:
CSVFileExists = File.Exists( Path.ChangeExtension( file, "csv" ) )
但那是多余的。
我也可以做一个恼人的多重选择,我手动复制属性,然后添加新的:
var data = blgFiles.Select( file => new
{
BLGFile = file,
CSVFile = Path.ChangeExtension( file, "csv" )
} );
var data2 = data.Select( file => new
{
BLGFile = file.BLGFile,
CSVFile = file.CSVFile,
CSVFileExists = File.Exists( file.CSVFile )
} );
我只是想知道……还有别的办法吗?我正在寻找可以快速添加属性和创建对象的方法,其中一些属性依赖于先前属性的值。
你无能为力。另一个选择:
var data = blgFiles.Select( file =>
{
csvFile = Path.ChangeExtension( file, "csv" );
return new
{
BLGFile = file,
CSVFile = csvFile ,
CSVFileExists = File.Exists( csvFile )
}
});
仍然有额外花括号的开销,并且需要显式的返回语句,这使得在这种形式和简化形式之间进行切换有点麻烦。(除非你使用Resharper,它可以帮你完成)
您可以"添加属性并创建对象,其中一些属性依赖于先前属性的值",只需要有"先前"属性。对象初始化器将所有属性设置为一条语句,这就是它的思想。
然而,您可以在select的lambda表达式中创建一个匿名方法来返回您想要的对象。在里面,你可以编写任意的c#代码,这将允许你有多个语句,所以你将有"以前"的语句。
编辑:示例代码已经作为答案
这可能不是您的问题的最佳示例,因为实际上您应该生成两个文件列表,并将它们连接起来,如:
var blgFiles = Directory.GetFiles( rootFolder, "*.blg", SearchOption.AllDirectories );
var csvFiles = Directory.GetFiles( rootFolder, "*.csv", SearchOption.AllDirectories );
var data = blgFiles.GroupJoin(csvFiles,
k=>Path.GetFilenameWithoutExtension(k),
v=>Path.GetFilenameWithoutExtension(v),
(k,g)=>g.Select(v=>new {BLGFILE=k,CSVFILE=v,CSVFileExists=true})
.DefaultIfEmpty(new {BLGFILE=k,CSVFILE=Path.ChangeExtension(k,"csv"),CSVFile=false})
).SelectMany(g=>g);
或者使用单个目录查找:
var files=Directory.EnumerateFiles(rootFolder, "*.*", SearchOption.AllDirectories)
.Where(s => s.EndsWith(".blg") || s.EndsWith(".csv"));
然后将它们分组,并生成最终输出。这可能是最快的解决方案,因为磁盘I/O相对昂贵,并且只执行一次这部分可能比其他任何考虑都重要。
当然,你总是可以这样做,但我怀疑你是在试图避免它:
var blgFiles = Directory.GetFiles( rootFolder, "*.blg", SearchOption.AllDirectories );
var data = blgFiles.Select( file => new
{
BLGFile = file,
CSVFile = Path.ChangeExtension( file, "csv" ),
CSVFileExists = File.Exists(Path.ChangeExtension( file, "csv" ))
} );
但是这会产生大量额外的磁盘I/O,并调用ChangeExtension两次。一个更简单的版本也可以使用,但存在同样的缺陷:
var data = blgFiles.Select( file => new
{
BLGFile = file,
CSVFile = Path.ChangeExtension( file, "csv" )
} ).Select( file => new
{
BLGFile = file.BLGFile,
CSVFile = file.CSVFile,
CSVFileExists = File.Exists( file.CSVFile )
} );