mercredi 21 avril 2021

C# - Create an instance of a class with generic type parameters without specifying these types

I have the following code:

public static class Typing
{
    public static void Run()
    {
        var type = typeof(GenericSuperType<,>);

        type = type.MakeGenericType(typeof(int), typeof(int));
        dynamic instance = Activator.CreateInstance(type);
        var types = instance.Register();
        
        foreach(var i in types)
            Console.WriteLine(i);
    }
}

public class GenericSuperType<C, R>
{
    public IEnumerable<Type> Register()
    {
        yield return typeof(MiddlewareOne<C, R>);
        yield return typeof(MiddlewareTwo<C, R>);
    }
}

public interface IGenericMiddleware<C, R>
{
    R Execute(C command);
}

public class MiddlewareOne<C, R> : IGenericMiddleware<C, R>
{
    public R Execute(C command)
    {
        return default;
    }
}

public class MiddlewareTwo<C, R> : IGenericMiddleware<C, R>
{
    public R Execute(C command)
    {
        return default;
    }
}

What I want to achieve is to create an instance of GenericSuperType<,> class in order to call the Register() method that will basically return some other generic types. The sole purpose for this is to get the types the Register() method returns (those types could be different than the ones in the example and would be provided by a user in a method overload). However, in order to do that, I need to provide some types to GenericSuperrType<,> (as I do with int) here, but then the problem rises - these types can have generic constraints on them, let's say:

public class GenericSuperType<C, R> where C : ISomeType
{
    public IEnumerable<Type> Register()
    {
        yield return typeof(MiddlewareOne<C, R>);
        yield return typeof(MiddlewareTwo<C, R>);
    }
}

In that case, creating the instance with whatever type will fail.
What I have tried so far is to check the generic constraints on C and R and act accordingly, something alog those lines (a simple example):

    public static void Run()
    {
        var type = typeof(GenericSuperType<,>);

        var defparams = type.GetGenericArguments();
        IList<Type> typeConstraints = new List<Type>();
        foreach (var i in defparams)
        {
            typeConstraints.Add(i.GetGenericParameterConstraints().FirstOrDefault());
        }

        for (int i = 0; i < typeConstraints.Count; i++)
        {
            if (typeConstraints[i] == null)
                typeConstraints[i] = typeof(String);
        }

        type = type.MakeGenericType(typeof(int), typeof(int));
        dynamic instance = Activator.CreateInstance(type);
        var types = instance.Register();
        
        foreach(var i in types)
            Console.WriteLine(i);
    }

And that would work OK but I'd have to cover all possible generic constraints.
The other thing I thought about is: to actually remove the GenericSuperType<,> generic type constraints with reflection (if it's actually possible, I think that should be but I'm not great at c# reflection), and then provide some dummy type just to get the types from the Register() method. Or maybe just copy the content of the type/class/file into another one without the generic type constraints and call them? I'm looking for solution to this (I know this sounds complicated but I also know that reflection is a powerful tool that would make that possible).

Thank you in advance for all your help!





Aucun commentaire:

Enregistrer un commentaire