geek
geek

Reputation: 616

Check if type is derived from abstract generic class

I need to get all types that derive from some abstract generic class. I also need to get generic type (like GetGenericArguments() on type that implement generic interface).

This is sample code:

public abstract class AbstractValidator<T>

public class CreateTripValidator : AbstractValidator<CreateTrip>

public class CancelTripValidator : AbstractValidator<CancelTrip>

I want to load all types that derive from AbstractValidator. In this example CreateTripValidator and CancelTripValidator. And I want check type of generic argument for each of them.

I tried in this way but none of them works:

var types = Assembly.GetExecutingAssembly().GetTypes().Where(
                    t => t.IsSubclassOf(typeof(AbstractValidator<>)));

var types = Assembly.GetExecutingAssembly().GetTypes().Where(
                    t => t.IsAssignableFrom(typeof(AbstractValidator<>)));

Upvotes: 4

Views: 3118

Answers (3)

Viktor Lova
Viktor Lova

Reputation: 5034

You must to check with your own hands all base types:

private static bool IsSubclassOfRawGeneric(Type baseType, Type derivedType) {
    while (derivedType != null && derivedType != typeof(object)) {
        var currentType = derivedType.IsGenericType ? derivedType.GetGenericTypeDefinition() : derivedType;
        if (baseType == currentType) {
            return true;
        }

        derivedType = derivedType.BaseType;
    }
    return false;
}

And then you can use it like this:

    var validatorType = typeof(AbstractValidator<>);
    var subTypes = validatorType.Assembly
        .GetTypes()
        .Where(t => IsSubclassOfRawGeneric(validatorType, t));

Ideone: R7Q88Z

Upvotes: 3

Lee
Lee

Reputation: 144206

static bool IsValidatorType(Type t)
{
    while(t != null)
    {
        if(t.IsGenericType && t.GetGenericTypeDefinition == typeof(AbstractValidator<>))
        {
            return true;
        }
        t = t.BaseClass;
    }
    return false;
}

var validatorTypes = Assembly.GetExecutingAssembly().GetTypes()
    .Where(IsValidatorType);

Upvotes: 4

Dan Bryant
Dan Bryant

Reputation: 27515

You can't look for derivation from the unconstructed generic type. You'll have to explicitly call Type.GetGenericTypeDefinition() on the BaseType to check if it equals typeof(AbstractValidator<>).

Note that this kind of thing is often easier if you use a marker interface like 'IAbstractValidator' which is non-generic, perhaps exposing non-generic wrapper methods for use by consumers that don't know the exact type. If you use that, you can make use of IsAssignableFrom, though you have to be careful not to get it backwards. You'll want typeof(IAbstractValidator).IsAssignableFrom(type) to get the correct check. This particular method is really easy to flip around because it seems analogous to if (x is type).

Upvotes: 1

Related Questions