使用Linq和Reflection选择元数据

时间:2010-06-27 00:53:53

标签: linq generics reflection .net-3.5

情况如下: 我正在尝试获取程序集中所有类型的集合,这些集合实现了特定的通用接口以及使用的泛型类型参数。我已经设法将一个Linq查询放在一起执行此操作,但它似乎非常冗长。

我已经阅读了let和join,但看不清楚如何使用它们来减少此特定查询的详细程度。任何人都可以提供有关如何缩短/增强查询的任何提示吗?

这是一个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;
        }
    }
}

此致

马特

1 个答案:

答案 0 :(得分: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(); 

let关键字有点像变量声明,但它存在于LINQ查询中 - 它允许您创建一个变量,该变量存储查询后面多个位置所需的结果。你也提到了“连接”,但这主要用于类似数据库的连接(我不确定它在这里是如何应用的)。