Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create an instance of generic type whose constructor requires a delegate function parameter?

I need to use the following generic class and method ParseFrom() in it:

public sealed class MessageParser<T> : MessageParser where T : IMessage<T>
{
    public MessageParser(Func<T> factory); //constructor
    public T ParseFrom(byte[] data);
}

Now, I do not know the type of the parameter for this class at compile time, so I use type reflection and MakeGenericType() method to do that:

//Assuming itemInstance is given as input parameter 
Type typeArgument = itemInstance.GetType();
Type genericClass = typeof(MessageParser<>);
var genericType = genericClass.MakeGenericType(typeArgument);
var instance = Activator.CreateInstance(genericType);

It gives me a runtime error: MessageParser<> does not have a parameterless constructor. But when I try to pass Func<T> factory as a parameter for CreateInstance():

var instance = Activator.CreateInstance(genericType, () => Activator.CreateInstance(typeArgument));

it gives me a compile error: Cannot convert lambda expression to type 'string' because it is not a delegate type. Am I using the wrong syntax for a delegate function here?

like image 277
BohdanZPM Avatar asked Aug 19 '21 14:08

BohdanZPM


People also ask

How do I create an instance in C sharp?

You declare an instance constructor to specify the code that is executed when you create a new instance of a type with the new expression. To initialize a static class or static variables in a non-static class, you can define a static constructor.

Can constructor be generic in C#?

No, generic constructors aren't supported in either generic or non-generic classes.


1 Answers

Constructing a delegate of an unknown type dynamically isn't as easy as using reflection to call a method, so the easiest option is to just write a statically typed method to construct the delegate, and then just call it using reflection.

public class DelegateCreator
{
    public static Func<T> MakeConstructorStatically<T>()
    {
        return Activator.CreateInstance<T>;
    }

    public static object MakeConstructorDynamically(Type type)
    {
        return typeof(DelegateCreator)
            .GetMethod(nameof(MakeConstructorStatically))
            .MakeGenericMethod(type)
            .Invoke(null, Array.Empty<object>());
    }
}
like image 156
Servy Avatar answered Oct 22 '22 04:10

Servy