Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get all inherited classes of a generic abstract class

I'm looking for some way to get all classes that inherit a generic abstract class, and perform a method on each of those classes.

I've been following this Change parameter type when implementing an abstract method to have the class implementations I want, something similar to this:

public abstract class AbstractRequest<TResponseData>
                where TResponseData : IResponseData
{
    public abstract void Search();
    public abstract GoodData BindData(TResponseData data);
}

public interface IResponseData
{
}

public class AResponse : IResponseData
{
}

public class BResponse : IResponseData
{
}

public class A : AbstractRequest<AResponse>
{
    public override void Search()
    {
        // get AResponse
        // Call to BindData() with AResponse
    }
    public override GoodData BindData(AResponse data)
    {
        // Bind the data from AResponse to GoodData
    }
}

public class B : AbstractRequest<BResponse>
{
    public override void Search()
    {
        // Get BResponse
        // Call to BindData() with BResponse
    }
    public override GoodData BindData(BResponse data)
    {
        // Bind the data from BResponse to GoodData
    }
}    

This is working find, until I need to get all the A & B class and invoke the Search() method for each of the classes. With a non-generic abstract class, I could use the following snippet to get the classes

var instances = from t in Assembly.GetExecutingAssembly().GetTypes()
                where t.IsSubclassOf(typeof(AbstractRequest))
                    && t.GetConstructor(Type.EmptyTypes) != null
                select Activator.CreateInstance(t) as AbstractRequest;

Then, how can I get all the classes A and B that inherit from AbstractRequest<AResponse> and AbstractRequest<BResponse>?

Edit: I forgot to mention. Let's assume that there will be many implementations similar to A or B, and will be added over time. I would like to have an "elegant" (if possible) solution so later on, I only need to take care of the implementation C, D, etc.

Thanks!

like image 239
Ngoc Pham Avatar asked Oct 08 '14 16:10

Ngoc Pham


2 Answers

Actually getting the instance to invoke Search() (and only search) can be done by breaking up the abstract class:

public abstract class AbstractRequest
{
    public abstract void Search();
}

public abstract class AbstractRequest<TResponseData> : AbstractRequest
            where TResponseData : IResponseData
{
    public abstract GoodData BindData(TResponseData data);
}

And then you can use your original (non-generic) code:

var instances = from t in Assembly.GetExecutingAssembly().GetTypes()
    where t.IsClass &&
          typeof(AbstractRequest).IsAssignableFrom(t) &&
          t.GetConstructor(Type.EmptyTypes) != null
    select Activator.CreateInstance(t) as AbstractRequest;

(Old, busted solution)

I think that I would do something like this (untested):

var abstractRequestTypes =
    (from t in Assembly.GetExecutingAssembly().GetTypes()
     where t.IsClass &&
          typeof(IResponseData).IsAssignableFrom(t)
     select typeof(AbstractRequest<>).MakeGenericType(t)).ToList();

var instanceTypes = from t in Assembly.GetExecutingAssembly().GetTypes()
    where t.IsClass &&
          abstractRequestTypes.Any(dt => dt.IsAssignableFrom(t));

This should cover anything in the inheritance hierarchy, taking advantage of the type constraint on AbstractRequest.

like image 189
Steve Czetty Avatar answered Sep 20 '22 09:09

Steve Czetty


Something like this should do the trick:

from t in Assembly.GetExecutingAssembly().GetTypes()
where t.IsClass && 
      (typeof(AbstractRequest<AResponse>).IsAssignableFrom(t) ||
       typeof(AbstractRequest<BResponse>).IsAssignableFrom(t))
select t;

Or if you wanna get all classes that inherit from generic class AbstractRequest you can use:

from t in Assembly.GetExecutingAssembly().GetTypes()
where t.IsClass && 
      t.BaseType != null &&
      t.BaseType.GetGenericTypeDefinition() == typeof(AbstractRequest<>)
select t;
like image 44
Selman Genç Avatar answered Sep 21 '22 09:09

Selman Genç