【问题标题】:Selecting metadata using Linq and Reflection使用 Linq 和反射选择元数据
【发布时间】:2011-03-08 17:55:57
【问题描述】:

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

我已经阅读了 let 和 joins,但不知道如何使用它们来减少这个特定查询的冗长。任何人都可以提供有关如何缩短/增强查询的任何提示吗?

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

问候,

马特

【问题讨论】:

    标签: linq generics reflection .net-3.5


    【解决方案1】:

    这是一个示例,说明如何使用 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 查询中 - 它允许您创建一个变量来存储查询稍后在多个位置需要的一些结果。您也提到了“联接”,但这主要用于类似数据库的联接(我不确定它在此处如何应用)。

    【讨论】:

    • 托马斯,你是个艺术家,这很好用,谢谢。我的原始示例不支持这一点,但我想知道如果它使用不同的类型参数多次实现接口,是否可以多次选择一个类型。在这种情况下会使用联接吗?
    • 啊,我现在掌握了这个 Linq 东西的窍门,我使用第二个 'from' 语句代替了 'let ifc = ...' 来管理它
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多