silent_coder
silent_coder

Reputation: 6502

check if instance inherited from generic or non generic version of a class in C#

so I have inheritance chain like this:

class a : {}
class a<T> : {}
class b: a<int> {}
class c: a {}

and I need to check if instance (let's say var inst = new b()) inherited from a<> or from a only.

however, nothing of standard IsAssignableFrom, IsSubclassOf, IsInstanceOfType, is don't fit.

What is a proper way to do this?

UPD1: Inheritance chain could be deeper than 1 level

Upvotes: 3

Views: 402

Answers (6)

user1023602
user1023602

Reputation:

class a : {}
class a<T> : {}

I'm sorry, but in C# a and a<T> are completely different. The fact that they both start with the letter a is a coincidence.

So to tell the difference, you can use the is operator.

 if (inst is a)
 {
    // derived from a
 }
 else 
 {
    // not derived from a
 }

Upvotes: 0

Dennis
Dennis

Reputation: 37770

Assuming, that you have this hierarchy:

class a { }
class a<T> : a { }
class b : a<int> { }
class c : a { }

you need to explore inheritance tree to get base generic types and test their generic type definitions. But if you looking for some generic-purpose solution, you have to take into account interface implementation case.

E.g., if your hierarchy will be rewritten like this:

interface a { }
interface a<T> : a { }
class b : a<int> { }
class c : a { }

this will "break" inheritance tree traversal, because base type of b will be System.Object instead of a<T>. That is, inheritance and interface implementations are two different things.

I'd implement it this way:

internal static class TypeExtensions
{
    private static bool IsInheritedFromGenericTypeDefinition(Type type, Type baseType)
    {
        do
        {
            if (type.IsGenericType && type.GetGenericTypeDefinition() == baseType)
                return true;

            type = type.BaseType;
        }
        while (type != null);

        return false;
    }

    public static bool IsInheritedFrom(this Type type, Type baseType)
    {
        if (baseType.IsGenericTypeDefinition)
        {
            if (!type.IsInterface && baseType.IsInterface)
            {
                do
                {
                    // since baseType is an interface, and source type is not,
                    // we can't test inheritance tree anymore;
                    // instead, we have to obtain implemented interfaces and test them
                    var implementedInterfaces = type.GetInterfaces();
                    if (implementedInterfaces.Any(intf => IsInheritedFromGenericTypeDefinition(intf, baseType)))
                        return true;

                    type = type.BaseType;
                }
                while (type != null);

                return false;
            }
            else
                return IsInheritedFromGenericTypeDefinition(type, baseType);
        }

        return baseType.IsAssignableFrom(type);
    }
}

Results:

a -> a<> = True

b -> a<> = True
b -> a = True
b -> a = True

c -> a = True
c -> a<> = False

Upvotes: 1

Jcl
Jcl

Reputation: 28272

With your update (more inheritance levels), you could have this:

public static bool IsGenericA(object instance)
{
    Type t = instance.GetType();
    while(t.BaseType != null && t.BaseType != typeof(object))
      t = t.BaseType;
    return t.IsGenericType && t.GetGenericTypeDefinition() == typeof(a<>);
}

public static bool IsNonGenericA(object instance)
{
    Type t = instance.GetType();
    while(t.BaseType != null && t.BaseType != typeof(object))
      t = t.BaseType;
    return t == typeof(a);
}

See it in action in this fiddle

Should work for any levels as long as the base is a or a<something>

Upvotes: 1

Cheng Chen
Cheng Chen

Reputation: 43513

A instance of class b is not derived from a<T>, but from a<int>, the two are different types.

var type = inst.GetType();
var result = false;

while (type != typeof(object))
{
    type = type.BaseType;
    if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(a<>))
    {
        result = true;
        break;
    }
}

//check result

Upvotes: 3

Gy&#246;rgy Kőszeg
Gy&#246;rgy Kőszeg

Reputation: 18013

b is not inherited from a<>, it is inherited from a<int>. However, you can check by reflection whether the generic type definition of the base class is a<>:

type t = typeof(b).BaseType;
return t.IsGenericType && t.GetGenericTypeDefinition() == typeof(a<>);

Upvotes: 1

Shiwanka Chathuranga
Shiwanka Chathuranga

Reputation: 889

how about typeOf() ? you can get parent classes using this

Upvotes: 0

Related Questions