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!
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
.
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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With