0

Sorry for the odd question wording.. I understand the concept but my google skills are lacking today.

I have a method that allows me to specify a generic to use for its work. Any class that gets passed in will inherit a class of "BaseProduct". This allows me to write code like the following.

SyncProductsByType<PublicationProduct>();
SyncProductsByType<ApparelProduct>();
.... etc

I just want to do a foreach on the basetype's subclasses, but I can't get the syntax right. So far, I have:

Type parentType = typeof(BaseProduct);
Assembly assembly = Assembly.GetExecutingAssembly();
Type[] types = assembly.GetTypes();
IEnumerable<Type> subclasses = types.Where(t => t.BaseType == parentType);

but thats ALL WRONG for use in a foreach. I can't figure out how to do this sort of thing:

foreach (<T> subclasse yadda yadda) {
    SyncProductsByType<something?>();
}

Thats not even close. Thanks

Edit: I don't believe this is a duplicate because there is an assumption that I'm trying to Invoke a method in all classes of type . No, what I'm trying to do is call a method against all derives types against a single method.

CarComp
  • 1,929
  • 1
  • 21
  • 47
  • 4
    Possible duplicate of [How do I use reflection to call a generic method?](https://stackoverflow.com/questions/232535/how-do-i-use-reflection-to-call-a-generic-method) – thehennyy Oct 25 '19 at 12:10
  • How do i use that answer? I can't get the syntax right. – CarComp Oct 25 '19 at 12:16
  • @CarComp as the answer says, you need to get the `MethodInfo` for your type -- `var methodInfo = typeof(EnclosingType).GetMethod("SyncProductsByType")`. Then you can call it with each member of `subclasses`: `methodInfo.MakeGenericMethod(subclass).Invoke(...)` – canton7 Oct 25 '19 at 12:24
  • See edit. I'm trying to be more clear what I'm asking – CarComp Oct 25 '19 at 12:28
  • Ohhhhhhhhhhhhh....Marked as duplicate. – CarComp Oct 25 '19 at 12:30

3 Answers3

1

You could do the following:

public class Test
{
    public static void SyncProductsByType<T>() where T : BaseProduct
    {
        // this method is a simple wrapper with constraint

        SyncProductsByType(typeof(T));
    }

    public static void SyncProductsByType(Type type)
    {
        // decide whether this should public, private or internal

        if (type.BaseType != typeof(BaseProduct))
            throw new ArgumentOutOfRangeException(nameof(type));

        // do work
    }
}

public abstract class BaseProduct
{
}

public class ApparelProduct : BaseProduct
{
}
aybe
  • 15,516
  • 9
  • 57
  • 105
  • I don't see where that will call `SyncProductsByType` against all derived types of `BaseProduct`. Additionally, I already have the static method `SyncProductsByType` written. I don't know how to iterate all derived baseproduct types against it. Thanks though – CarComp Oct 25 '19 at 12:24
  • The definition `SyncProductsByType(Type)` allows you to call such method in your `foreach` loop. – aybe Oct 25 '19 at 12:30
  • It is a duplicate. Sorry all. Brain isn't working this morning. – CarComp Oct 25 '19 at 12:31
1

You can find all descendant classes and then invoke the generic method this way:

class Program
{
    class BaseClass
    {
        public static void Generic<T>() where T : BaseClass
        {
            Console.WriteLine(typeof(T).Name);
        }
    }
    class FirstClass : BaseClass
    {

    }
    class SecondClass : BaseClass
    {

    }
    static void Main(string[] args)
    {
        MethodInfo method = typeof(BaseClass).GetMethod("Generic");

        foreach (var item in Assembly.GetExecutingAssembly().GetTypes()
                                        .Where(myType => myType.IsClass && myType.IsSubclassOf(typeof(BaseClass))))
        {
            MethodInfo generic = method.MakeGenericMethod(item);
            generic.Invoke(null, null);
        }
    }
}

Edit: A little optimalization.

turanszkik
  • 494
  • 5
  • 15
  • Take the call to `typeof(BaseClass).GetMethod("Generic")` out of the loop. It's relatively expensive, and doesn't need to be repeated for each `item`. – canton7 Oct 25 '19 at 12:55
  • 1
    @canton7 Yeah you are right, reflection isn't the fastest. I corrected it for the sake of accuracy. – turanszkik Oct 25 '19 at 13:00
0

I think what you are looking for is Type.IsSubclassOf this check if a type is a subclass of another type. The only way to invoke a method with said Type object is by getting a generic definition MethodInfo and then using MakeGenericMethod to create a generic method which has T set to the specified Type, for example:

Type parentType = typeof(BaseProduct);

Assembly assembly = Assembly.GetExecutingAssembly();

Type[] types = assembly.GetTypes();

var genericDefinition = typeof(BaseClass).GetMethod("SyncProductsByType");

foreach (Type type in types)
{
    if (type.IsSubclassOf(parentType))
    {
        genericDefinition.MakeGenericMethod(type).Invoke(instance, null);
    }
}
Vincent Bree
  • 425
  • 4
  • 10