2013-10-22 105 views
4

这个单语句查询很整洁地说:“给我一个文件名为包含特定文件结构的ZIP存储库的文件名列表。”如何使用一致的语法重写此LINQ表达式?

但我同时使用.Where()扩展方法(流畅的语法)和一个选择查询,因为我尝试其他任何事情都无法编译。如果我将“Where(文件==> <语句>)”更改为“<语句>”,则会出现匿名方法代码不会返回bool的错误,并且如果更改“选择<子句>”到“。选择(<子句>)”,错误是“没有使用select子句”。

我很高兴与查询或流利的语法,但我想解决一个或另一个。任何人都可以解释为什么这不起作用,我需要做什么来解决一个一致的语法?

return (from file in Directory.EnumerateFiles(
        Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), Globals.CompanyName, ProjectName, FolderName), 
        imageExtension, 
        SearchOption.TopDirectoryOnly) 
    .Where(file => 
    { 
     try 
     { 
      string relativePath = ClassFru.Station + "/"; // Inside ZIPs, paths use a single forward slash 
      var zip = new ZipFile(); 
      zip.ZipError += (s, o) => { throw new Exception(); }; 
      using (zip = ZipFile.Read(file)) 
      { 
       /// <todo>if (zip.Comment != Globals.CompanyName) { return false; }</todo> 
       foreach (var fru in this.gFrus) 
       { 
        var fruPath = relativePath + fru.Id + '.'; 
        if (!(from e in zip where !e.IsDirectory && e.FileName.StartsWith(fruPath) select true).Any()) { return false; } 
       } 
       return true; 
      } 
     } 
     catch (Exception) 
     { 
      return false; 
     } 
    }) 
    select Path.GetFileNameWithoutExtension(file)).ToArray(); 
+0

我认为这可能是其中几个'foreach'列举更容易理解的情况之一:) –

+4

那个'Where'的内容几乎肯定不应该是一个匿名方法;这应该是一个命名方法,以便您可以编写像'.Where(DirectoryIsValid)'或类似的东西。 – Servy

+0

你得到“不使用select子句”的原因是因为你也有'from'。将整个东西转换为方法语法,或者像Servy所说的那样将lambda提取到方法中。 –

回答

3

因为我不知道你在使用这个表达式是挺难编译它,但所有类型的,我认为我应该像那:

  return (Directory.EnumerateFiles(
      Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), 
       Globals.CompanyName, ProjectName, FolderName), 
      imageExtension, 
      SearchOption.TopDirectoryOnly) 
      .Where(file => { 
       try 
       { 
        string relativePath = ClassFru.Station + "/"; // Inside ZIPs, paths use a single forward slash 
        var zip = new ZipFile(); 
        zip.ZipError += (s, o) => { 
         throw new Exception(); 
        }; 
        using (zip = ZipFile.Read(file)) 
        { 
         /// <todo>if (zip.Comment != Globals.CompanyName) { return false; }</todo> 
         foreach (var fru in this.gFrus) 
         { 
          var fruPath = relativePath + fru.Id + '.'; 
          if(zip.Any(e=> !e.IsDirectory && e.FileName.StartsWith(fruPath)) 
            .Any()) 
          { 
           return false; 
          } 
         } 
         return true; 
        } 
       } catch (Exception) 
       { 
        return false; 
       } 
      }).Select(Path.GetFileNameWithoutExtension).ToArray()); 
+0

很好的答案,非常感谢你,但是我最喜欢这个,因为它实际上给出了简洁的工作代码,没有典型的(ha!)宗教战争。代码WAS的原始版本使用命名方法,但因为查询是大型方法的一部分,所以它将实现与引用分离了很长距离。对我来说,这更好,因为它说我想在一个地方。 – shipr

1

除了改变使用selectSelect(file =>您还需要在开始时删除from file in。然后,您将删除使用该查询语法select子句。这是唯一的from子句导致了你所看到的错误。每个from [...] in子句都需要匹配select

+0

+1我不知道为什么我以前从未注意到,当我看到。选择)我没有看到从条款。我总是发现查询语法更具可读性,但我慢慢学习的不同。 – shipr

0

我很高兴与查询或流利的语法,但我想解决一个或另一个。任何人都可以解释为什么这不起作用,我需要做什么来解决一个一致的语法?

它不适合你,因为LINQ并没有真正处理复杂逻辑的大块作为条件。特别是,LINQ Expression语法假设您将提供表达式(而不是块),因此它不直接支持多行语句。

如果您只是删除from部分的查询,您可以很容易地获得方法语法,如ISun shows you how to do

另一方面,如果您只是简单地提取匿名方法,您的代码将更容易理解和模块化,正如@Servy在评论中所建议的那样。在这种情况下,你可以决定说where FileHasMatchingZipStructure(file)。或.Where(FileHasMatchingZipStructure),如你所愿。