2011-03-16 131 views
3

我有一個foreach循環,我想用一個Linq查詢替換,但我一直無法弄清楚如何編寫查詢。請看下面的例子和TIA。是否有可能用Linq替換這個foreach循環?

using System.Collections.Generic; 
using System.Linq; 

namespace ConsoleApplication 
{ 
    class ExampleProgram 
    { 
     static void Main(string[] args) 
     { 
      Device device = new Device(); 

      // The goal is to populate this list. 
      var list1 = new List<IMemory>(); 

      // I would like to replace this loop with a Linq query 
      foreach(MemoryBank memoryBank in device.MemoryBanks) 
      {    
       list1.Add(memoryBank); // add the memory bank 

       foreach(MemoryBlock memoryBlock in memoryBank.MemoryBlocks) 
        list1.Add(memoryBlock); // add the memory block 
      } 

      //var list2 = from memoryBank in device.MemoryBanks 
      //   from memoryBlock in memoryBank.MemoryBlocks 
      //   select ???; 
     } 
    } 

    interface IMemory 
    {} 

    public class Device 
    { 
     public IList<MemoryBank> MemoryBanks { get; set; } 
    } 

    public class MemoryBank : MemoryBlock, IMemory 
    { 
     public IList<MemoryBlock> MemoryBlocks { get; set; } 
    } 

    public class MemoryBlock : IMemory 
    { } 
} 
+1

嗯,可以。但是,當你在進行LINQ查詢時需要考慮超過5分鐘的時候,那麼你就知道有什麼不對。 – Euphoric 2011-03-16 15:48:24

+0

@Euphoric如果你在編程中採用這種方法,將很難擴展你的知識。花5分鐘在這裏和那裏學習一些東西,最終可能會獲得回報。 – jsmith 2011-03-16 15:51:33

+0

@jsmith:它不是關於我。它關於其他程序員。如果我看到人們提出的疑問,我會困惑至少5分鐘。但原創從一開始就清澈透明。 – Euphoric 2011-03-16 15:53:45

回答

5

你可以這樣做:

var list1 = device.MemoryBanks 
        .SelectMany(m => new[] { m }.Concat(m.MemoryBlocks)) 
        .ToList(); 

請注意,這將創建一個List<MemoryBlock>而非List<IMemory>作爲樣本。要製作接口類型列表,請致電ToList<IMemory>()

編輯:

在.NET 3.5,其中IEnumerable<T>接口不是協變的,你可以這樣做:

var list1 = device.MemoryBanks 
        .SelectMany(m => new IMemory[] { m } 
             .Concat(m.MemoryBlocks.Cast<IMemory>())) 
        .ToList(); 
+0

'Concat()'不會抱怨,因爲'new [] {m​​}'的隱含類型是'IEnumerable '而不是'IEnumerable '? – BrokenGlass 2011-03-16 15:53:13

+0

@BrokenGlass:在.NET 4中,接口的協方差意味着「IEnumerable 」也是「IEnumerable 」,這是第一個樣本所依賴的。 'IEnumerable '依次是'IEnumerable ',你可以依靠它來調用'ToList ()'。 – Ani 2011-03-16 16:02:06

+0

明白了,感謝您的額外解釋 - 因此'Concat()'創建的枚舉類型將是兩個輸入枚舉共享的界面層次結構中的第一個類型(從特定類型直到「IMemory」),正確? - 協變讓我每一次(和+1) – BrokenGlass 2011-03-16 17:13:56

1

像這樣的東西應該工作:

list1 = device.MemoryBanks 
       .Select(x=> x.MemoryBlocks.AsEnumerable<IMemory>().Concat(x)) 
       .SelectMany(x=>x) 
       .ToList();