Проверьте, является ли класс производным от универсального класса - PullRequest
280 голосов
/ 19 января 2009

В моем проекте есть общий класс с производными классами.

public class GenericClass<T> : GenericInterface<T>
{
}

public class Test : GenericClass<SomeType>
{
}

Есть ли способ узнать, является ли объект Type производным от GenericClass?

t.IsSubclassOf(typeof(GenericClass<>))

не работает.

Ответы [ 16 ]

4 голосов
/ 12 марта 2013

Опираясь на превосходный ответ выше fir3rpho3nixx и Дэвида Шмитта, я изменил их код и добавил тест ShouldInheritOrImplementTypedGenericInterface (последний).

    /// <summary>
    /// Find out if a child type implements or inherits from the parent type.
    /// The parent type can be an interface or a concrete class, generic or non-generic.
    /// </summary>
    /// <param name="child"></param>
    /// <param name="parent"></param>
    /// <returns></returns>
    public static bool InheritsOrImplements(this Type child, Type parent)
    {
        var currentChild = parent.IsGenericTypeDefinition && child.IsGenericType ? child.GetGenericTypeDefinition() : child;

        while (currentChild != typeof(object))
        {
            if (parent == currentChild || HasAnyInterfaces(parent, currentChild))
                return true;

            currentChild = currentChild.BaseType != null && parent.IsGenericTypeDefinition && currentChild.BaseType.IsGenericType
                                ? currentChild.BaseType.GetGenericTypeDefinition()
                                : currentChild.BaseType;

            if (currentChild == null)
                return false;
        }
        return false;
    }

    private static bool HasAnyInterfaces(Type parent, Type child)
    {
        return child.GetInterfaces().Any(childInterface =>
            {
                var currentInterface = parent.IsGenericTypeDefinition && childInterface.IsGenericType
                    ? childInterface.GetGenericTypeDefinition()
                    : childInterface;

                return currentInterface == parent;
            });

    }

    [Test]
    public void ShouldInheritOrImplementNonGenericInterface()
    {
        Assert.That(typeof(FooImplementor)
            .InheritsOrImplements(typeof(IFooInterface)), Is.True);
    }

    [Test]
    public void ShouldInheritOrImplementGenericInterface()
    {
        Assert.That(typeof(GenericFooBase)
            .InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
    }

    [Test]
    public void ShouldInheritOrImplementGenericInterfaceByGenericSubclass()
    {
        Assert.That(typeof(GenericFooImplementor<>)
            .InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
    }

    [Test]
    public void ShouldInheritOrImplementGenericInterfaceByGenericSubclassNotCaringAboutGenericTypeParameter()
    {
        Assert.That(new GenericFooImplementor<string>().GetType()
            .InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
    }

    [Test]
    public void ShouldNotInheritOrImplementGenericInterfaceByGenericSubclassNotCaringAboutGenericTypeParameter()
    {
        Assert.That(new GenericFooImplementor<string>().GetType()
            .InheritsOrImplements(typeof(IGenericFooInterface<int>)), Is.False);
    }

    [Test]
    public void ShouldInheritOrImplementNonGenericClass()
    {
        Assert.That(typeof(FooImplementor)
            .InheritsOrImplements(typeof(FooBase)), Is.True);
    }

    [Test]
    public void ShouldInheritOrImplementAnyBaseType()
    {
        Assert.That(typeof(GenericFooImplementor<>)
            .InheritsOrImplements(typeof(FooBase)), Is.True);
    }

    [Test]
    public void ShouldInheritOrImplementTypedGenericInterface()
    {
        GenericFooImplementor<int> obj = new GenericFooImplementor<int>();
        Type t = obj.GetType();

        Assert.IsTrue(t.InheritsOrImplements(typeof(IGenericFooInterface<int>)));
        Assert.IsFalse(t.InheritsOrImplements(typeof(IGenericFooInterface<String>)));
    } 
2 голосов
/ 20 декабря 2017

@ EnocNRoll - ответ Ананды Гопала интересен, но в случае, если экземпляр не был создан заранее или вы хотите проверить с помощью определения общего типа, я бы предложил этот метод:

public static bool TypeIs(this Type x, Type d) {
    if(null==d) {
        return false;
    }

    for(var c = x; null!=c; c=c.BaseType) {
        var a = c.GetInterfaces();

        for(var i = a.Length; i-->=0;) {
            var t = i<0 ? c : a[i];

            if(t==d||t.IsGenericType&&t.GetGenericTypeDefinition()==d) {
                return true;
            }
        }
    }

    return false;
}

и используйте его как:

var b = typeof(char[]).TypeIs(typeof(IList<>)); // true

В четырех условных случаях t (подлежит проверке) и d являются универсальными типами, а два случая охватываются t==d, которые (1) не являются ни t, ни d является общим определением или (2) оба они являются общими определениями . В остальных случаях одним из них является общее определение, только когда d уже является общим определением, у нас есть шанс сказать, что a t является d, но не наоборот.

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

2 голосов
/ 22 января 2010

JaredPar,

Это не сработало, если я передал typeof (type <>) как toCheck. Вот что я изменил.

static bool IsSubclassOfRawGeneric(Type generic, Type toCheck) {
    while (toCheck != typeof(object)) {
        var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
          if (cur.IsGenericType && generic.GetGenericTypeDefinition() == cur.GetGenericTypeDefinition()) {
            return true;
        }
        toCheck = toCheck.BaseType;
    }
    return false;
}
0 голосов
/ 17 ноября 2016

опоздал к игре на этом ... у меня тоже есть еще одна перестановка ответа JarodPar.

здесь Type.IsSubClassOf (Type) любезно предоставлено отражателем:

    public virtual bool IsSubclassOf(Type c)
    {
        Type baseType = this;
        if (!(baseType == c))
        {
            while (baseType != null)
            {
                if (baseType == c)
                {
                    return true;
                }
                baseType = baseType.BaseType;
            }
            return false;
        }
        return false;
    }

Исходя из этого, мы видим, что он не делает ничего слишком умного и похож на итеративный подход JaredPar. Все идет нормально. вот моя версия (отказ от ответственности: не полностью проверен, поэтому позвольте мне знать, если вы обнаружите проблемы)

    public static bool IsExtension(this Type thisType, Type potentialSuperType)
    {
        //
        // protect ya neck
        //
        if (thisType == null || potentialSuperType == null || thisType == potentialSuperType) return false;

        //
        // don't need to traverse inheritance for interface extension, so check/do these first
        //
        if (potentialSuperType.IsInterface)
        {
            foreach (var interfaceType in thisType.GetInterfaces())
            {
                var tempType = interfaceType.IsGenericType ? interfaceType.GetGenericTypeDefinition() : interfaceType;

                if (tempType == potentialSuperType)
                {
                    return true;
                }
            }
        }

        //
        // do the concrete type checks, iterating up the inheritance chain, as in orignal
        //
        while (thisType != null && thisType != typeof(object))
        {
            var cur = thisType.IsGenericType ? thisType.GetGenericTypeDefinition() : thisType;

            if (potentialSuperType == cur)
            {
                return true;
            }

            thisType = thisType.BaseType;
        }
        return false;
    }

в основном это просто метод расширения для System.Type - я сделал это, чтобы преднамеренно ограничить тип "thisType" конкретными типами, так как я сразу же использую запрос LINQ "где" для предикатов объектов Type. я уверен, что все вы, умные люди, могли бы столкнуть его с эффективным, универсальным статическим методом, если вам нужно :) код делает несколько вещей, код ответа которых не делает

  1. открыть это до общего "расширения" - я рассматриваю наследование (думаю, классы) а также реализация (интерфейсы); имена методов и параметров изменены, чтобы лучше отражать это
  2. Ввод нулевой проверки (МЭА)
  3. ввод того же типа (класс не может расширяться сам)
  4. выполнение короткого замыкания, если рассматриваемый тип является интерфейсом; поскольку GetInterfaces () возвращает все реализованные интерфейсы (даже реализованные в суперклассах), вы можете просто перебрать эту коллекцию, не поднимаясь по дереву наследования

остальное в основном совпадает с кодом JaredPar

0 голосов
/ 17 марта 2016

Вы можете попробовать это расширение

    public static bool IsSubClassOfGenericClass(this Type type, Type genericClass,Type t)
    {
        return type.IsSubclassOf(genericClass.MakeGenericType(new[] { t }));
    }
0 голосов
/ 24 марта 2009
Type _type = myclass.GetType();
PropertyInfo[] _propertyInfos = _type.GetProperties();
Boolean _test = _propertyInfos[0].PropertyType.GetGenericTypeDefinition() 
== typeof(List<>);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...