Выбор метаданных с помощью Linq и Reflection - PullRequest
0 голосов
/ 27 июня 2010

Вот ситуация: Я пытаюсь получить коллекцию всех типов в моей сборке, которые реализуют определенный универсальный интерфейс вместе с используемыми параметрами универсального типа. Мне удалось собрать запрос Linq для выполнения этого, но он выглядит ужасно избыточным.

Я перечитал let и объединения, но не мог понять, как их использовать, чтобы уменьшить многословность этого конкретного запроса. Кто-нибудь может дать какие-нибудь советы о том, как сократить / улучшить запрос, пожалуйста?

Вот класс 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 Ответ

2 голосов
/ 27 июня 2010

Вот пример, который показывает, как переписать это, используя ключевое слово 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 - это позволяет вамсоздать переменную, которая хранит некоторый результат, который необходим в нескольких местах позже в запросе.Вы также упоминаете «объединения», но в основном они используются для соединений, подобных базам данных (и я не уверен, как это будет применяться здесь).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...