在linq中构建对象 - 添加依赖于其他属性的属性

时间:2015-05-29 10:31:01

标签: c# linq

我经常对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 )
     } );

我只是想知道......还有其他方法吗?我正在寻找可以快速添加属性和创建对象的方法,其中某些属性取决于先前属性的值。

3 个答案:

答案 0 :(得分:2)

你无能为力。另一种选择:

 var data = blgFiles.Select( file => 
 {
   csvFile = Path.ChangeExtension( file, "csv" );
   return new
   {
      BLGFile = file,
      CSVFile = csvFile ,
      CSVFileExists = File.Exists( csvFile  )
   }
 });

它还有额外花括号的开销,需要一个显式的return语句,这使得在这个和简化形式之间切换有点麻烦。 (除非你使用Resharper,它会为你做。)

答案 1 :(得分:0)

您可以添加属性并创建对象,其中某些属性取决于先前属性的值",只需要"之前"属性。 对象初始化程序将所有属性设置为一个语句,这就是它的概念。

然而,您可以在select的lambda表达式中创建一个匿名方法,该方法返回您想要的对象。在里面,你可以编写任意C#代码,这将允许你有多个语句,所以你将拥有"之前的#34;的。

编辑:该示例代码已作为答案

答案 2 :(得分:0)

这可能不是您问题的最佳示例,因为您应该生成两个文件列表,并加入它们:

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