Combinar duas consultas LINQ?

votos
1

Eu acho que eu estou tendo um bloqueio mental, mas alguém por favor pode me esclarecer sobre como combinar estas duas declarações LINQ em um?

/// <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>();
}

Estou evitando IsAssignableFrom como parece falhar quando não fornecer o tipo específico da interface genérica pois acredito usando FullName caparison sobre IsAssignableFrom deve ser suficiente, por exemplo:

namespace Davide
{
    interface IOutput<TOutputType> { }

    class StringOutput : IOutput<string> { }
}

typeof (IOutput <>). FullName irá retornar Davide + IOutput`1

typeof (StringOutput) .GetInterfaces () [0] .FullName voltará Davide + IOutput`1 [[System.String, mscorlib, versão = 2.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089]]

Portanto, utilizando FullName.Contains deve ser suficiente

Publicado 10/12/2008 em 13:22
fonte usuário
Em outras línguas...                            


4 respostas

votos
1

isso vai fazer:

    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();
    }
Respondeu 10/12/2008 em 13:50
fonte usuário

votos
1

Posso sugerir outra solução?

    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>();
    }
Respondeu 10/12/2008 em 13:57
fonte usuário

votos
3

SelectMany se traduz em um segundo "de":

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;

Eu dividir condições em várias "onde" cláusulas de clareza subjetiva, btw.

Isso compila, mas eu não testei para ver se ele realmente funciona ou não :) Como outra resposta mostrou, você poderia usar "Qualquer" com GetInterfaces () em vez do final "da" cláusula.

Note-se que não há necessidade de manter chamando ToList () em todo o lugar - LINQ é projetado para ser capaz de trabalhar em seqüências todo.

By the way, eu não sei por que você está passando type.GetInterfaces () para verificar. Há algo diferente (e desejável) de que vs usando Type.IsAssignableFrom ? Isso tornaria mais simples:

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;

Você realmente tem o mesmo nome do tipo de interface em uma montagem diferente em algum lugar?

Respondeu 10/12/2008 em 14:11
fonte usuário

votos
0

Depois de uma breve discussão com Jon Skeet e um pouco mais pensamento, que eu postei a seguinte resposta. Eu alterei o método a utilizar GetGenericTypeDefinition em vez de FullName.Contains, esta seria uma solução mais robusta. Eu também alterou a consulta LINQ Onde cláusulas para IsAbstract e IsInterface como estes não excluiu tipos como esperado. Obrigado a todos por seus comentários.

/// <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>();
}
Respondeu 11/12/2008 em 15:08
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more