Combine two LINQ queries?

I think I have a mental block, but can someone please tell me how to combine these two LINQ operators into one?

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

      

I avoid IsAssignableFrom as it seems to fail when it doesn't supply a specific type of generic interface, so I believe that using FullName caparison over IsAssignableFrom should suffice, e.g .:

namespace Davide
{
    interface IOutput<TOutputType> { }

    class StringOutput : IOutput<string> { }
}

      

typeof (IOutput <>). FullName will return "Davide + IOutput`1"

typeof (StringOutput) .GetInterfaces () [0] .FullName will return "Davide + IOutput`1 [[System.String, mscorlib, Version = 2.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089]]"

Therefore using FullName.Contains should suffice

+1


source to share


4 answers


After a short discussion with Jon Skeet and a little more thoughtful, I posted the following answer. I changed the method using GetGenericTypeDefinition rather than FullName.Contains, this would be a more robust solution. I also modified the LINQ Where clauses for IsAbstract and IsInterface as they did not exclude types as expected. Thanks everyone for your feedback.



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

      

0


source


SelectMany translates to the second "from":

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;

      

I've split the clauses into several "where" clauses for subjective clarity, by the way.

This compiles, but I haven't tested if it actually works or not. As the other answer showed, you can use "Any" with GetInterfaces () instead of the final "from" clause.



Note that there is no need to constantly rewrite ToList () all over the place - LINQ is designed to work on sequences.

By the way, I'm not sure why you are passing through type.GetInterfaces () to check. Is there something different (and desirable) from this using Type.IsAssignableFrom ? This will make it easier:

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;

      

Do you actually have the same interface type name in another assembly?

+3


source


this will do:

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

      

+1


source


Can you suggest another solution?

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

      

+1


source







All Articles