Объединить два запроса LINQ?

Я думаю, что у меня психический блок, но может кто-нибудь просветить меня, как объединить эти два оператора LINQ в один?

/// <summary>
/// Returns an array of Types that implement the supplied generic interface in the
/// current AppDomain.
/// </summary>
/// <param name = "interfaceType">Type of generic interface implemented</param>
/// <param name = "includeAbstractTypes">Include Abstract class types in the search</param>
/// <param name = "includeInterfaceTypes">Include Interface class types in the search</param>
/// <returns>Array of Types that implement the supplied generic interface</returns>
/// <remarks>
/// History.<br/>
/// 10/12/2008      davide       Method creation.<br/>
/// </remarks>
public static Type[] GetTypesImplementingGenericInterface(Type interfaceType, bool includeAbstractTypes, bool includeInterfaceTypes)
{
    // Use linq to find types that implement the supplied interface.
    var allTypes = AppDomain.CurrentDomain.GetAssemblies().ToList()
                    .SelectMany(s => s.GetTypes())
                    .Where(p => p.IsAbstract == includeAbstractTypes  
                                    && p.IsInterface == includeInterfaceTypes);

    var implementingTypes = from type in allTypes
                            from intf in type.GetInterfaces().ToList()
                            where intf.FullName != null && intf.FullName.Contains(interfaceType.FullName)
                            select type;

    return implementingTypes.ToArray<Type>();
}

Я избегаю IsAssignableFrom, поскольку он, похоже, терпит неудачу, если не предоставляет конкретный тип универсального интерфейса, поэтому я считаю, что использование Caparison FullName вместо IsAssignableFrom должно быть достаточным, например:

namespace Davide
{
    interface IOutput<TOutputType> { }

    class StringOutput : IOutput<string> { }
}

typeof (IOutput <>). FullName вернет "Davide + IOutput`1"

typeof (StringOutput) .GetInterfaces () [0] .FullName вернет «Davide + IOutput`1 [[System.String, mscorlib, Version = 2.0.0.0, Culture = нейтральный, PublicKeyToken = b77a5c561934e089]]»

Поэтому использования FullName.Contains должно быть достаточно

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
6 493
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

это будет делать:

    public static Type[] GetTypesImplementingGenericInterface(Type interfaceType, bool includeAbstractTypes, bool includeInterfaceTypes)
    {
        // Use linq to find types that implement the supplied interface.
        var allTypes = AppDomain.CurrentDomain.GetAssemblies().ToList()
                                    .SelectMany(s => s.GetTypes())
                                    .Where(p => p.IsAbstract == includeAbstractTypes
                                           && p.IsInterface == includeInterfaceTypes
                                           && p.GetInterfaces().Any(i=>i.FullName != null && i.FullName.Contains(interfaceType.FullName))
                                           );

        //var implementingTypes = from type in allTypes
        //                        from intf in type.GetInterfaces().ToList()
        //                        where intf.FullName != null && intf.FullName.Contains(interfaceType.FullName)
        //                        select type;

        //return implementingTypes.ToArray<Type>();

        return allTypes.ToArray();
    }

Могу я предложить другое решение?

    public static Type[] GetTypesImplementingGenericInterface(Type interfaceType, bool includeAbstractTypes, bool includeInterfaceTypes)
    {
        // Use linq to find types that implement the supplied interface.
        var implementingTypes = AppDomain.CurrentDomain.GetAssemblies()
                                    .SelectMany(s => s.GetTypes())
                                    .Where(p => interfaceType.IsAssignableFrom(p)
                                              && (
                                                     (p.IsAbstract && includeAbstractTypes) 
                                                     || (p.IsInterface && includeInterfaceTypes)
                                                     || (!p.IsAbstract && !p.IsInterface)
                                                 )
                                          );

        return implementingTypes.ToArray<Type>();
    }

Спасибо, Бруно, ознакомьтесь с комментарием, который я сделал к сообщению Джона Скита об IsAssignableFrom, он может вас заинтересовать.

Student for Life 11.12.2008 01:07

SelectMany переводится как секунда "от":

var implementors = from assembly in AppDomain.CurrentDomain.GetAssemblies()
                   from type in assembly.GetTypes()
                   where type.IsAbstract == includeAbstractTypes
                   where type.IsInterface == includeInterfaceTypes
                   from intf in type.GetInterfaces()
                   where intf.FullName != null && 
                         intf.FullName.Contains(interfaceType.FullName)
                   select type;

Я разделил условия на несколько пунктов «где» для субъективной ясности, кстати.

Это компилируется, но я не проверял, работает ли это на самом деле или нет :) Как показал другой ответ, вы можете использовать «Any» с GetInterfaces () вместо последнего предложения «from».

Обратите внимание, что нет необходимости постоянно вызывать ToList () повсюду - LINQ предназначен для работы с последовательностями повсюду.

Кстати, я не уверен, почему вы используете type.GetInterfaces () для проверки. Есть ли что-то отличное (и желаемое) от этого по сравнению с использованием Тип. IsAssignableFrom? Так было бы проще:

var implementors = from assembly in AppDomain.CurrentDomain.GetAssemblies()
                   from type in assembly.GetTypes()
                   where type.IsAbstract == includeAbstractTypes
                   where type.IsInterface == includeInterfaceTypes
                   where interfaceType.IsAssignableFrom(type)
                   select type;

У вас действительно есть такое же имя типа интерфейса в другой сборке?

Изначально у меня был IsAssignableFrom, но я обнаружил, что когда вы предоставляете общий интерфейс без определенного типа, например. typeof (IInterface <>), он не работает, поскольку фактические классы реализуют определенные типы, например ConcreteClass: IInterface <string>, поэтому они не совпадают.

Student for Life 11.12.2008 01:06

@Davide: Тогда сравнение по имени тоже не сработает. Если вы так думаете, приведите полный пример :)

Jon Skeet 11.12.2008 01:55

@Jon: Я обновил вопрос примером (надеюсь, это имеет смысл), дайте мне знать, если вы думаете, что мне что-то не хватает при сравнении FullName. Честно говоря, это не мой предпочтительный метод, но я пока не уверен в альтернативе.

Student for Life 11.12.2008 06:36

Ах, я пропустил, что вы используете FullName.Contains, а не FullName ==. Лично я бы написал отдельный метод, чтобы сделать это «правильно» (используя GetGenericTypeDefinition), но если вас устраивает FullName, первый запрос выше должен работать.

Jon Skeet 11.12.2008 09:21

Джон, я опубликовал свой собственный ответ с окончательным решением, я нашел свою альтернативу (ура) и решил использовать GetGenericTypeDefinition, как обсуждалось. Спасибо за обсуждение, это помогло.

Student for Life 11.12.2008 17:12
Ответ принят как подходящий

После короткого обсуждения с Джоном Скитом и еще немного размышлений я опубликовал следующий ответ. Я изменил метод, чтобы использовать GetGenericTypeDefinition вместо FullName.Contains, это было бы более надежным решением. Я также изменил предложения Where в LINQ-запросе для IsAbstract и IsInterface, поскольку они не исключают типы, как ожидалось. Спасибо всем за ваш отзыв.

/// <summary>
/// Returns an array of Types that implement the supplied generic interface in the
/// current AppDomain.
/// </summary>
/// <param name = "interfaceType">Type of generic interface implemented</param>
/// <param name = "excludeAbstractTypes">Exclude Abstract class types in the search</param>
/// <param name = "excludeInterfaceTypes">Exclude Interface class types in the search</param>
/// <returns>Array of Types that implement the supplied generic interface</returns>
/// <remarks>
/// History.<br/>
/// 11/12/2008      davide       Created method.<br/>
/// 11/12/2008      davide       Altered method to use a two LINQ query pass.<br/>
/// 11/12/2008      davide       Altered method to use optimised combined LINQ query.<br/>
/// 12/12/2008      davide       Altered method and replaced FullName criteria match with GetGenericTypeDefinition.<br/>
/// </remarks>
public static Type[] GetTypesImplementingGenericInterface(Type interfaceType, bool excludeAbstractTypes, bool excludeInterfaceTypes)
{
    if (!interfaceType.IsGenericType)
    {
        throw new ArgumentException("Supplied interface is not a Generic type");
    }

    if (interfaceType.ContainsGenericParameters)
    {
        interfaceType = interfaceType.GetGenericTypeDefinition();
    }

    // Use linq to find types that implement the supplied generic interface.
    var implementingTypes = from assembly in AppDomain.CurrentDomain.GetAssemblies()
                            from type in assembly.GetTypes()
                            where (type.IsAbstract != excludeAbstractTypes) || (!excludeAbstractTypes)
                            where (type.IsInterface != excludeInterfaceTypes) || (!excludeInterfaceTypes)
                            from intf in type.GetInterfaces()
                            where intf.IsGenericType && intf.GetGenericTypeDefinition() == interfaceType
                            select type;

    return implementingTypes.ToArray<Type>();
}

Другие вопросы по теме