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

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

Related

Is there a way to declare a Func in C# with a generic type? [duplicate]

I like to send a generic type converter function to a method but I can't figure out how to do it.
Here's invalid syntax that explains what I like to achieve, the problem is I don't know how to specify the generic type together with my func:
public void SomeUtility(Func<T><object,T> converter)
{
var myType = converter<MyType>("foo");
}
Edit (see also my discussion in the comments with Lawrence) : By "generic type converter" I meant I would like to pass in a converter that can convert to any strong type <T> (not object), so the next line in my method could be:
var myOtherType = converter<MyOtherType>("foo");
The delegate I like to pass as a parameter would look something like this:
private delegate TOutput myConverterDelegate<TOutput>(object objectToConvert);
This is more a syntax / C# exploration now, to get things done I will probably use an interface instead, but I do hope this is possible to accomplish with a func/delegate.
You cannot have instances of generic functions or actions - all type parameters are defined upfront and cannot be redefined by the caller.
An easy way would be to avoid polymorphism altogether by relying on down-casting:
public void SomeUtility(Func<Type, object, object> converter)
{
var myType = (MyType)converter(typeof(MyType), "foo");
}
If you want type safety, you need to defer the definition of the type parameters to the caller. You can do this by composing a generic method within an interface:
public void SomeUtility(IConverter converter)
{
var myType = converter.Convert<MyType>("foo");
}
interface IConverter
{
T Convert<T>(object obj);
}
Edit:
If the 'converter type' is known at the call-site, and only this type will be used inside the utility method, then you can define a generic type on the method and use that, just like other posters have suggested.
public void SomeUtility<T>(Func<object, T> converter)
{
var myType = converter("foo");
}
and then:
SomeUtility(arg => new MyType());
The generic type inference will work in this case.
You need to make SomeUtility generic as well. Doing this and fixing the syntax gives:
public void SomeUtility<T>(Func<object,T> converter)
{
var myType = converter("foo");
}
You have to know the T type at compile-time to use it. The T can either be specified at class-level or at method-level.
class SomeClass<T> {
public void SomeUtility(Func<object, T> converter) {
var myType = converter("foo"); // Already is the T-type that you specified.
}
}
or
public void SomeUtility<T>(Func<object, T> converter) {
var myType = converter("foo"); // Already is the T-type that you specified.
}

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?
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[] { });
}

Generic class where type can Parse strings

I want to create a generic class where the type of the class can Parse strings.
I want to use this class for any class that has a static function Parse(string),
like System.Int32, System.Double, but also for classes like System.Guid. They all have a static Parse function
So my class needs a where clause that constraints my generic type to types with a Parse function
I'd like to use it like this:
class MyGenericClass<T> : where T : ??? what to do ???
{
private List<T> addedItems = new List<T>()
public void Add(T item)
{
this.AddedItems.Add(item);
}
public void Add(string itemAsTxt)
{
T item = T.Parse(itemAsTxt);
this.Add(item);
}
}
What to write in the where clause?
I was not happy with the answers that would use reflection to do the Parsing.
I prefer a solution that is type safe, so the compiler would complain about the a missing Parse function.
Normally you would constraint to a class that has an interface. But as others said, there is no common interface. Come to think of it I don't need an interface, I need a function that I can call
So my solution would be to insist that creators would provide a delegate to the Parse Function that would parse a string to type T
class MyGenericClass<T>
{
public MyGenericClass(Func<string, T> parseFunc)
{
this.parseFunc = parseFunc;
}
private readonly Func<string, T> parseFunc;
public void Add(string txt)
{
this.Add(parseFunc(txt));
}
}
Usage:
MyGenericClass<Guid> x = new MyGenericClass<Guid>(txt => Guid.Parse(txt));
MyGenericClass<int> y = new MyGenericClass<int> (txt => System.Int32.Parse(txt));
The answer is simpler than I thought
I might be misunderstanding your question, but will this do the trick?
static void Main(string[] args)
{
Guid g = DoParse<Guid>("33531071-c52b-48f5-b0e4-ea3c554b8d23");
}
public static T DoParse<T>(string value)
{
T result = default(T);
MethodInfo methodInfo = typeof(T).GetMethod("Parse");
if (methodInfo != null)
{
ParameterInfo[] parameters = methodInfo.GetParameters();
object classInstance = Activator.CreateInstance(typeof(T), null);
object[] parametersArray = new object[] { value };
result = (T)methodInfo.Invoke(methodInfo, parametersArray);
}
return result;
}
You can´t do that at compile-time at all. All those methods don´t have anything in common except their names. They neither are defined in any common interface nor have they the same parameters.
Imagine you have your own method that accidently has that name, but does something completely different. In addition it´s also an instance-method:
class MyType
{
void Parse() { ... }
}
As you can see that method don´t even has any argument, making it hard to find any common logic between - say - int.Parse(myString)andmyInstanceOfMyType.Parse()`.
But even if you could do that. What would you do with the item? There´s not much as there´s nothing in common between them. In particular it´s impossible to call the methpd, as they are completely different.
You could loop all types with a similar method at runtime however:
var types = allAssemblies.SelectMany(x => x.GetTypes())
.Where(x => x.GetMethod("Parse") != null);
But be aware that this yields to an AmbiguousMatchException if more than one method per type exists with the name, this is when the method is overloaded.

How can I pass in a func with a generic type parameter?

I like to send a generic type converter function to a method but I can't figure out how to do it.
Here's invalid syntax that explains what I like to achieve, the problem is I don't know how to specify the generic type together with my func:
public void SomeUtility(Func<T><object,T> converter)
{
var myType = converter<MyType>("foo");
}
Edit (see also my discussion in the comments with Lawrence) : By "generic type converter" I meant I would like to pass in a converter that can convert to any strong type <T> (not object), so the next line in my method could be:
var myOtherType = converter<MyOtherType>("foo");
The delegate I like to pass as a parameter would look something like this:
private delegate TOutput myConverterDelegate<TOutput>(object objectToConvert);
This is more a syntax / C# exploration now, to get things done I will probably use an interface instead, but I do hope this is possible to accomplish with a func/delegate.
You cannot have instances of generic functions or actions - all type parameters are defined upfront and cannot be redefined by the caller.
An easy way would be to avoid polymorphism altogether by relying on down-casting:
public void SomeUtility(Func<Type, object, object> converter)
{
var myType = (MyType)converter(typeof(MyType), "foo");
}
If you want type safety, you need to defer the definition of the type parameters to the caller. You can do this by composing a generic method within an interface:
public void SomeUtility(IConverter converter)
{
var myType = converter.Convert<MyType>("foo");
}
interface IConverter
{
T Convert<T>(object obj);
}
Edit:
If the 'converter type' is known at the call-site, and only this type will be used inside the utility method, then you can define a generic type on the method and use that, just like other posters have suggested.
public void SomeUtility<T>(Func<object, T> converter)
{
var myType = converter("foo");
}
and then:
SomeUtility(arg => new MyType());
The generic type inference will work in this case.
You need to make SomeUtility generic as well. Doing this and fixing the syntax gives:
public void SomeUtility<T>(Func<object,T> converter)
{
var myType = converter("foo");
}
You have to know the T type at compile-time to use it. The T can either be specified at class-level or at method-level.
class SomeClass<T> {
public void SomeUtility(Func<object, T> converter) {
var myType = converter("foo"); // Already is the T-type that you specified.
}
}
or
public void SomeUtility<T>(Func<object, T> converter) {
var myType = converter("foo"); // Already is the T-type that you specified.
}

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