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

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?

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>());
}
}

To create the Func<T> through reflection, CreateDelegate is the way to go. Therefore a method, that has the expected signature - including the type contraints (T is IMessage<T>)- is needed.
Here's how you can get it work.
A downside is, that you will still need to use reflection to invoke the parser's methods, at least those that work with the type parameter:
public class CreateParserLateBound {
//The method with the matching signature
public static T MessageParserFactory<T>()
where T : IMessage<T>
{
//your factory code, you pass to MessageParser(Func<T> factory) goes here...
return default(T);
}
...
// itemInstance == item that is IMesage<T>, with T unknown at compiletime;
var itemType = itemInstance.GetType();
var boundParserType = typeof(MessageParser<>).MakeGenericType(itemType);
var boundFuncType = typeof(Func<>).MakeGenericType(itemType);
var factoryMethodInstance = typeof(CreateParserLateBound )
.GetMethod("MessageParserFactory")
.MakeGenericMethod(itemType)
.CreateDelegate(boundFuncType);
var parserInstance = Activator.CreateInstance(boundParserType,
new object[]{ factoryMethodInstance } );
//Invoke ParseFrom (also through reflection)
byte[] data = {1,2,3,4};
boundParserType.InvokeMember("ParseFrom",
BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, null,
parserInstance, new object[] {data});
Full runnable code # https://dotnetfiddle.net/RIOEXA

The easy answer is to write your own generic method, then call that via reflection.
public static class Foo
{
public static MessageParser<T> CreateParser<T>() where T : IMessage<T>, new()
=> new MessageParser<T>(() => new T());
private static MethodInfo _createMethod = typeof(Foo)
.GetMethods()
.Where(m => m.Name == nameof(CreateParser) && m.IsGenericMethod)
.Single();
public static MessageParser CreateParser(Type type)
=> (MessageParser)_createMethod.MakeGenericMethod(type)
.Invoke(null, new object[] { });
}

Related

Activator.CreateInstance with Delegate parameter

I want to create an instance of an internal class from a third party assembly with reflection.
The class looks like this
internal sealed class SomeClass
{
public delegate object SomeDelegate(object value);
public SomeDelegateHandler { get; private set; }
public SomeClass(SomeDelegate handler)
{
this.Handler = handler;
}
}
Usually I would use reflection to create instances of an internal class but I need to pass a SomeDelegate delegate.
Since that delegate is inside the internal class I need to create an instance of that delegate via reflection, too. But everything I already tried, did not work
This is what I tried so far.
// This is the method that I need to pass as an argument
public static object SomeDelegateImplementation(object value)
{
return value;
}
public void Main()
{
// example: create SomeClass without reflection
// (this is how SomeClass is usually constructed);
var instance = new SomeClass(SomeDelegateImplementation);
// setup: get the ConstructorInfo so I can use
// ctor.Invoke(...) to create an instance of that class
var assembly = typeof(ThirdParty.OtherClass).Assembly;
var type = assembly.GetType("ThirdParty.SomeClass", true, true);
var ctor = type.GetConstructors()[0];
// method one (doesn't work)
// compiler error: cannot convert method group 'SomeDelegateImplementation' to non-delegate type 'object'. Did you intend to invoke the method?
var args = new object[]{ SomeDelegateImplementation };
var instance = ctor.Invoke(args);
// method two (doen't work)
// throws a runtime error during invoke:
// error converting object with type "System.Func`2[System.Object,System.Object]" to type "ThirdParty.SomeClass+SomeDelegate".
Func<object, object> someDelegateImplementation = SomeDelegateImplementation;
var args = new object[]{ (Delegate)someDelegateImplementation };
var instance = ctor.Invoke(args);
}
Solution
Thanks to #JonSkeet I manged to create an instance of SomeClass with using Delegate.CreateDelegate
Assembly assembly = typeof(ThirdParty.OtherClass).Assembly;
Type type = assembly.GetType("ThirdParty.SomeClass", true, true);
ConstructorInfo ctor = type.GetConstructors()[0];
// get a reference to the original delegate type
Type someDelegateHandler Type =
assembly.GetType("ThirdParty.SomeClass+SomeDelegateHandler", true, true);
// get a reference to my method
MethodInfo someDelegateImplementationMethod =
typeof(Program).GetMethod("SomeDelegateImplementation",
BindingFlags.Static | BindingFlags.NonPublic);
// create a delegate that points to my method
Delegate someDelegateImplementationDelegate =
Delegate.CreateDelegate(
someDelegateHandler, someDelegateImplementationMethod);
object[] args = new object[]{ someDelegateImplementationDelegate };
object instance = ctor.Invoke(args);

How do I create a delegate for a property getter from an open generic type

I have a PropertyInfo for a property on an open generic type, obtained in the following way:
public interface ITest<T>
{
T Item { get; }
}
var propertyInfo = typeof(ITest<>).GetProperty("Item");
I'd like to be able to create a concrete, callable delegate, filling in the class type parameter (e.g. Func<ITest<int>, int>) from propertyInfo.
The obvious thing to try is propertyInfo.GetMethod.MakeGenericMethod(typeof(int)).CreateDelegate(...), but this fails because GetMethod isn't generic - it's a property on a generic class.
I know you can get a delegate for this property by applying the type parameter to the type earlier on (e.g. typeof(ITest<int>).GetProperty("Item").GetMethod.CreateDelegate(...)), but I was hoping to only have to look for the property in ITest once, given that it'll be the same search repeated for each type parameter otherwise.
Is there a way to create this delegate, or can it only come about by using typeof(ITest<int>) to start with?
Short Version
Can TestMethod below be made to pass by some implementation of CreateGetter (assuming T::Equals is implemented sensibly)?
public void TestMethod<T>(ITest<T> x)
{
var propertyInfo = typeof(ITest<>).GetProperty("Item");
var getter = CreateGetter<int>(propertyInfo);
Assert(getter(x).Equals(x.Item));
}
You need to instantiate the generic type first and then you can create the delegate from the MethodInfo in the usual way.
var target = typeof(ITest<>).MakeGenericType(typeof(int));
var prop = target.GetProperty("Item");
var dlg = prop.GetMethod.CreateDelegate(typeof(Func<,>).MakeGenericType(target, prop.PropertyType));
If you actually want to use a PropertyInfo, this Method will work:
public static Func<Test<T>, T> CreateGetter<T>(PropertyInfo info)
{
Type type = info.ReflectedType;
PropertyInfo genericProperty = type.MakeGenericType(typeof(T)).GetProperty(info.Name);
return (source) => (T)genericProperty.GetValue(source);
}
Otherwise i would suggest this:
public static Func<Test<T>, T> GetGenericPropertyDelegate<T>(string propertyName)
{
PropertyInfo genericProperty = typeof(Test<>).MakeGenericType(typeof(T)).GetProperty(propertyName);
return (source) => (T)genericProperty.GetValue(source);
}
usage:
public void Test<T>(ITest<T> x)
{
var getter = GetGenericPropertyDelegate<int>("Item");
Assert(getter(x).Equals(x.Item));
}

Pass dynamically type to generic template

I am facing an issue with the reflection in C#. I need to construct a generic method that instantiate a class type dynamically with reflection. What I tried is the following.
Type myClass = Type.GetType(deviceBehavior.#class);
Type myInterfaceClass = myClass.GetInterface(deviceBehavior.#interface);
if (typeof (AnotherInterface).IsAssignableFrom(interfaceClass))
{
CreateManager<interfaceClass>(serviceProvider, deviceCapability);
}
My CreateManager method is as following:
private void CreateManager<T>(ServiceProvider serviceProvider, DeviceCapability deviceCapability)
{
T instanceToCreate = CreateClass<T>(serviceProvider, deviceCapability);
//Code to instantiate my class
}
The problem is that I can't call
CreateManager(serviceProvider, deviceCapability);
How can I pass an interface to my generic type? I searched and I couldn't find anything that I could understand clearly. i.e.
Calling a static method on a generic type parameter
Pass An Instantiated System.Type as a Type Parameter for a Generic Class
Lets say CreateManager<T> is a method of type Foo:
public class Foo
{
private void CreateManager<T>(ServiceProvider serviceProvider,
DeviceCapability deviceCapability)
{
}
}
In order to dynamically invoke the generic method, you'll need to get the MethodInfo first, then call MakeGenericMethod with the actual type you want to pass (I choose string for the example)
var foo = new Foo();
var createManagerMethod = foo.GetType()
.GetMethod("CreateManager",
BindingFlags.Instance | BindingFlags.NonPublic);
var method = createManagerMethod.MakeGenericMethod(typeof(string));
method.Invoke(foo, new object[] { new ServiceProvider(), new DeviceCapability() });
Finally, call Invoke with the proper object instance and parameters.
I don't see, why you need reflection for this. You could do it like shown below
public interface IYourInterface //Give it a good name
{
void Instantiate(ServiceProvider serviceProvider, DeviceCapability deviceCapability);
}
public class YourClass : IYourInterface
{
public YourClass()
{
// do something if you want
}
public void Instantiate (ServiceProvider serviceProvider, DeviceCapability deviceCapability)
{
// what ever needs to be done here
}
}
private void CreateManager<T>(ServiceProvider serviceProvider, DeviceCapability deviceCapability)
where T : IYourInterface, new()
{
var instance = new T();
instance.Instantiate(serviceProvider, deviceCapability);
}
/*
Usage
*/
CreateManager<YourClass>(serviceProvider, deviceCapability);

Generic class instance with type from PropertyInfo.PropertyType

I have classes like below:
public class SampleClassToTest<T>
{
public static Fake<T> SomeMethod(string parameter)
{
// some code
}
public static Fake<T> SomeMethod(string parameter, int anotherParameter)
{
//some another code
}
}
public class Fake<T>
{
// some code
}
And I want to use them in this way:
SampleClassToTest<MyClass>.SomeMethod("some parameter");
The problem which I have is the following: type of "MyClass" I can get only from PropertyInfo instance using Reflection, so I have
Type propertyType = propertyInfo.PropertyType;
How can I do this? Any ideas?
UPD. I'm trying to pass the Type to generic method. And yes, this is what I want.
You would need to do:
typeof(SampleClassToTest<>).MakeGenericType(propertyType)
.GetMethod("SomeMethod", new Type[] {typeof(string)})
.Invoke(null, new object[] {"some parameter"});
Ugly.
If it can at all be helped, I would advise offering a non-generic API that accepts a Type instance; the nice thing here is that a generic API can call into a non-generic API trivially by using typeof(T).
It looks like you want:
Type propertyType;
Type classType = typeof(SampleClassToTest<>).MakeGenericType(propertyType);
MethodInfo method = classType.GetMethod("SomeMethod", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(string) }, null);
object fake = method.Invoke(null, new object[] { "some parameter" });

Returning System.Action from static method on generic type with types defined at runtime

Below is a very paired down example of what I am trying to achieve
public class CoolClass<T>
{
public static void DoSomethingCool()
{
// Insert cool generic stuff here.
List<T> coolList = new List<T>();
}
}
public class OtherClass
{
public Action ReturnActionBasedOnStaticGenericMethodForType(Type type)
{
// Ideally this would just be
return CoolClass<type **insert magic**>.DoSomethingCool
}
}
I know if the type is known I can do following and it will return System.Action
return CoolClass<string>.DoSomethingCool
I know if all I wanted to do was invoke the method I can do
Type baseType = typeof(CoolClass<>);
Type[] typeArguments = new [] {type}
Type constructedType = baseType.MakeGenericType(typeArguments);
MethodInfo method = constructedType.GetMethod("DoSomethingCool");
method.Invoke(null,null);
I maybe down the wrong path all together. It seems like I am trying go get method to be a reference to DoSomethingCool method. I am wishing for something like (Action) method.
You're nearly there - you just need Delegate.CreateDelegate:
Action action = (Action) Delegate.CreateDelegate(typeof(action), null, method);

Categories

Resources