Как узнать, реализует ли тип объекта IEnumerable <X>, где X происходит из Основы с помощью Отражения

Дайте базовый класс Base, Я хочу записать Тест метода, как это:

private static bool Test(IEnumerable enumerable)
{
...
}

таким образом, что Тест возвращает true, если тип o реализует какой-либо интерфейс IEnumerable<X> где X происходит из Base, так, чтобы, если я сделал бы это:

public static IEnumerable<string> Convert(IEnumerable enumerable)
{
    if (Test(enumerable))
    {
        return enumerable.Cast<Base>().Select(b => b.SomePropertyThatIsString);
    }

    return enumerable.Cast<object>().Select(o => o.ToString());
}

... то, что это сделало бы правильную вещь, с помощью Отражения. Я уверен, что это - вопрос обхода через все интерфейсы типа для нахождения первого, которое соответствует требованиям, но мне нелегко находить дженерик IEnumerable<> среди них.

Конечно, я мог рассмотреть это:

public static IEnumerable<string> Convert(IEnumerable enumerable)
{
    return enumerable.Cast<object>().Select(o => o is Base ? ((Base)o).SomePropertyThatIsString : o.ToString());
}

... но думайте о нем как о мысленном эксперименте.

5
задан Thomas Levesque 31 March 2010 в 23:17
поделиться

2 ответа

Вы также можете использовать запрос LINQ , который может выглядеть следующим образом.

public static bool ImplementsBaseType(IEnumerable objects)
{
    int found = ( from i in objects.GetType().GetInterfaces()
                 where i.IsGenericType && 
                       i.GetGenericTypeDefinition() == typeof(IEnumerable<>) &&
                       typeof(MyBaseClass).IsAssignableFrom(i.GetGenericArguments()[0])
                 select i ).Count();

    return (found > 0);
}

Этот код предполагает следующие операторы using:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

Поскольку это всего лишь мысленный эксперимент. Вот еще одна реализация в качестве метода расширения.

public static class ConversionAssistants
{
    public static bool GenericImplementsType(this IEnumerable objects, Type baseType)
    {
        foreach (Type type in objects.GetType().GetInterfaces())
        {
            if (type.IsGenericType)
            {
                if (type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
                {
                    if (baseType.IsAssignableFrom(type.GetGenericArguments()[0]))
                        return true;
                }
            }
        }
        return false;
    }
}
16
ответ дан 18 December 2019 в 13:12
поделиться

Вы можете использовать Type.FindInterfaces , чтобы отфильтровать все IEnumerable <> интерфейсы, которые тип реализует и проверьте общие параметры (через Type.GetGenericArguments ) для каждого из них, чтобы узнать, является ли он Base или наследуется от Base .

Обновление : Вот пример кода:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace ConsoleApplication1
{
    class Base
    {
        string Prop { get; set;}
    }

    class A : Base
    {
    }

    class Test : List<A>
    {
    }

    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Test test = new Test();
                Type myType = test.GetType();

                //string filterCriteria = "IEnumerable`1";
                Type typeA = Type.GetType("ConsoleApplication1.A");
                string filterCriteria = "System.Collections.Generic.IEnumerable`1[[" +
                                        typeA.AssemblyQualifiedName +
                                        "]]";

                // Specify the TypeFilter delegate that compares the 
                // interfaces against filter criteria.
                TypeFilter myFilter = new TypeFilter(MyInterfaceFilter);
                Type[] myInterfaces = myType.FindInterfaces(myFilter,
                    filterCriteria);
                if (myInterfaces.Length > 0)
                {
                    Console.WriteLine("\n{0} implements the interface {1}.",
                        myType, filterCriteria);
                    for (int j = 0; j < myInterfaces.Length; j++)
                        Console.WriteLine("Interfaces supported: {0}.",
                            myInterfaces[j].ToString());
                }
                else
                    Console.WriteLine(
                        "\n{0} does not implement the interface {1}.",
                        myType, filterCriteria);
            }
            catch (ArgumentNullException e)
            {
                Console.WriteLine("ArgumentNullException: " + e.Message);
            }
            catch (TargetInvocationException e)
            {
                Console.WriteLine("TargetInvocationException: " + e.Message);
            }
            catch (Exception e)
            {
                Console.WriteLine("Exception: " + e.Message);
            }
        }

        public static bool MyInterfaceFilter(Type typeObj, Object criteriaObj)
        {
            // This will be true, if criteria is
            // System.Collections.Generic.IEnumerable`1[[ConsoleApplication1.A, ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
            if (typeObj.FullName == criteriaObj.ToString())
                return true;
            // This will be true, if criteria is
            // IEnumerable`1
            // You will still need to check the generic parameters on the original type
                // (generic parameters are not exposed on Type instances for interfaces
            else if (typeObj.Name == criteriaObj.ToString())
                return true;
            else
                return false;
        }
    }
}
0
ответ дан 18 December 2019 в 13:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: