2010-06-27 77 views
0

這裏的情況: 我試圖讓我的組件實現與使用泛型類型參數沿特定的通用接口的所有類型的集合。我已經成功地將一個Linq查詢放在一起來執行此操作,但它似乎非常冗餘。選擇使用LINQ和反射元

我開始,讓閱讀並加入卻不見如何我會用它們來減少這種特定查詢的詳細程度。任何人都可以提供關於如何縮短/增強查詢的任何提示嗎?

下面是目前通過和MSTest的類演示了我想要實現:

[TestClass] 
public class Sample 
{ 
    [TestMethod] 
    public void MyTest() 
    { 
     var results = 
      (from type in Assembly.GetExecutingAssembly().GetTypes() 
      where type.GetInterfaces().Any(x => 
        x.IsGenericType && 
        x.GetGenericTypeDefinition() == typeof(MyInterface<,>) 
       ) 
      select new ResultObj(type, 
       type.GetInterfaces().First(x => 
        x.IsGenericType && 
        x.GetGenericTypeDefinition() == typeof(MyInterface<,>) 
       ).GetGenericArguments()[0], 
       type.GetInterfaces().First(x => 
        x.IsGenericType && 
        x.GetGenericTypeDefinition() == typeof(MyInterface<,>) 
       ).GetGenericArguments()[1] 
      )).ToList(); 

     Assert.AreEqual(1, results.Count); 
     Assert.AreEqual(typeof(int), results[0].ArgA); 
     Assert.AreEqual(typeof(string), results[0].ArgB); 
    } 

    interface MyInterface<Ta, Tb> 
    { } 
    class MyClassA : MyInterface<int, string> 
    { } 

    class ResultObj 
    { 
     public Type Type { get; set; } 
     public Type ArgA { get; set; } 
     public Type ArgB { get; set; } 
     public ResultObj(Type type, Type argA, Type argB) 
     { 
      Type = type; 
      ArgA = argA; 
      ArgB = argB; 
     } 
    } 
} 

問候,

馬特

回答

2

這裏展示瞭如何使用重寫這樣的例子let關鍵字:

var results = 
    (from type in Assembly.GetExecutingAssembly().GetTypes() 
    // Try to find first such interface and assign the result to 'ifc' 
    // Note: we use 'FirstOrDefault', so if it is not found, 'ifc' will be null 
    let ifc = type.GetInterfaces().FirstOrDefault(x => 
       x.IsGenericType && 
       x.GetGenericTypeDefinition() == typeof(MyInterface<,>)) 
    // Filtering and projection can now use 'ifc' that we already have 
    where ifc != null 
    // Similarly to avoid multiple calls to 'GetGenericArguments' 
    let args = ifc.GetGenericArguments() 
    select new ResultObj(type, args[0], args[1])).ToList(); 

T他let關鍵字的工作有點像變量聲明,但LINQ查詢中生活 - 它允許你創建存儲一些結果稍後在查詢需要在多個地方的變量。你也提到「連接」,但主要用於類似數據庫的連接(我不確定它是如何應用的)。

+0

托馬斯,你是一個藝術家,這個完美的作品,謝謝。 我原來的例子並不支持這一點,但我想知道是否有可能選擇一種類型多次,如果它有不同的類型參數實現的接口不止一次。在這種情況下會使用連接嗎? – Matt 2010-06-27 09:21:08

+0

啊,我得到的這個LINQ的東西的竅門現在,我管理的到位,使用「從」聲明第二的「讓IFC = ...」 – Matt 2010-06-27 09:38:23