c# generic method + reflection question - c#

In C# I want to create a generic method that:
Accepts a MethodInfo object as a parameter.
Returns the object that is returned when the MethodInfo is invoked.
The source of my confusion is that I want the method to be generically typed to the same return type as the MethodInfo object that gets passed in.

You cannot do this. By definition, generics are a compile-time construct, while the return type of a particular MethodInfo is something that is only known at runtime (when you receive a specific MethodInfo instance), and will change from call to call.

Pavel Minaev is right,
My suggestion in this case (of course i don't know the whole context) is use a method that returns a dynamic type, of course is that wouldn't be typed.
public dynamic MyMethod(MethodInfo methodInfo)
Or since you know what is the return type, put that in the method call:
public T MyMethod<T>(MethodInfo methodInfo)
of course you gonna get in trouble inside the method mapping the conversions.
but you can also put the conversion in a parameter using lambda, like:
public T MyMethod<T>(MethodInfo methodInfo, Func<object, T> conversion)
i think the call of the method will be very clear, like:
Console.WriteLine(MyMethod(methodInfo, (a) => Convert.ToString(a)));

Related

Delegate with generic type only known at runtime

In my code I have declared an interface as follows:
interface IGeneric
{
T GetOfType<T>();
}
And I want to invoke the interface's method with a generic type only known at runtime. This is how I do it currently, and it works:
Type genericArgument = ...
object interfaceImplementation = ...
MethodInfo methodInfo = typeof(IGeneric).GetMethod("GetOfType").MakeGenericMethod(genericArgument);
methodInfo.Invoke(interfaceImplementation, null);
but because I have to call this part of code quite often, I would like to cache the method info in a delegate. I tried this delegate definition
private delegate T GetOfTypeDelegate<T>();
and tried to create a delegate using the method info I retrieved like shown above like this:
GetOfTypeDelegate<?> deleg = (GetOfTypeDelegate<?>) Delegate.CreateDelegate(typeof(GetOfTypeDelegate<?>), methodInfo);
but since I don't know the type of the generic argument at compile time, I don't know what to put where I used the ? or how to make this work at all.
Any help is gladly appreciated.
I'd advise having generic and non-generic versions of the method, much like List<T> implements IEnumerable<T> while also explicitly implementing System.Collections.IEnumerable.
"Type known only at runtime" is exactly what generics aren't intended to be used for. The way you're calling this method, you only ever get object out of it anyway. Better to have a real ordinary non-generic method that just returns object.
T GetOfType<T>();
object GetOfType(Type t);
You don't even need to worry about overload resolution. There's some extra burden placed on the class implementing the interface, admittedly. But as you've seen, there's going to be a burden somewhere.

Method called without passing parameters

I'm a beginner in C#. I encountered below code snippet in my project. I do not understand how ViewHelper.IsInView has been called without passing any parameters. Could anyone explain me this. Thanks in advance.
public static class ViewHelper
{
public static bool IsInView(IFrameworkElement element)
{
----------
}
}
var Result = Views.Any(ViewHelper.IsInView);
The Any method accepts a delegate - a pointer to a function - of the form Func<T, bool>. Meaning it expects a method that accepts an element of the type of the collection (I'm guessing IFrameworkElement in your case) and returns a bool - which is exactly the signature of the IsInView method.
The Any method then executes this delegate on elements in the Views collection until it encounters one that returns true.
In C#, there is an implicit conversion from a "method group" to a delegate type. Essentially, when you write
Views.Any(ViewHelper.IsInView)
It translates into
Views.Any(new Func<IFrameworkElement, bool>(ViewHelper.IsInView))
What is being passed to Enumerable.Any is a delegate, the method is not being called at this point. If there are any views then Any will call that delegate with one or more of the views as the argument.
The delegate you're passing to Any has been created through something known as implicit method group conversion.
Views.Any is expecting a delegate of the type Func<IFrameworkElement, bool>, meaning it takes a single parameter of type IFrameworkElement and returns bool. You can create such a delegate from your method, as the signatures are compatible. This is how you would explicitly do this:
Func<IFrameworkElement, bool> predicate =
new Func<IFrameworkElement, bool>(ViewHelper.IsInView);
However, from C# 2.0 such a conversion can be done implicitly, meaning this code is exactly the same:
Func<IFrameworkElement, bool> predicate = ViewHelper.IsInView;

How to set a type dynamically into a generic method?

Say you have this generic method:
public static T ConvertValue<T, U>(U value) where U : IConvertible
{
return (T)Convert.ChangeType(value, typeof(T));
}
If I want to call this method inside another generic method. The outer generic method must receive as arguments the actual argument values to set <T, U>(U value) of the inner generic method.
How to achieve this properly, so that I can call OuterGeneric and feed it with the appropriate arguments?
This is just a demonstration of how I need to use it.
public void OuterGeneric<TypeT, TypeU>(TypeT tType, TypeU uType, TypeU valueOfTypeU)
{
// Call of Generic method
TypeT recieverOf_T = ConvertValue<tType, uType>(valueOfTypeU);
}
// Some way to call OuterGeneric. How?
Just call ChangeType directly. You're wrapping the call in a method that requires the type to be specified at compile time, rather than runtime, and then asking how to call it when the type is only known at runtime. You already had a method (ChangeType) that does exactly that.
You don't need method parameters for the generic types in your outer method. You should be able to just use the type parameters like this:
public void OuterGeneric<TypeT, TypeU>(TypeU valueOfTypeU)
{
// Call of Generic method
TypeT recieverOf_T = ConvertValue<TypeT, TypeU>(valueOfTypeU);
}
Then call OuterGeneric the way you would any other generic method.
Your question is a little unclear because you used the term "dynamically." Of course generic parameters must be known at compile time, so if you're looking for a way to use generic methods when only knowing the types at runtime, then you don't actually want to use .NET generics.

Creating Delegates of an unavailable return type

Assume we have a static method "Instance" in a type: "SomeType"
MethodInfo instanceMethod = SomeType.GetMethod("Instance");
The method returns an object of a type that is not available in my code as it does not reference the assembly where that class is defined.
I would like then, to cast it to "object"
Like this:
Delegate.CreateDelegate(typeof(Func<object>), null, "Instance")
However I get this exception:
System.ArgumentException: Error binding to target method.
The CreateDelegate overload that you appear to be using only works for instance methods, not static ones. If you pass the MethodInfo instead of the name "Instance", you'll be using an overload that will work.
Also, Func<object> isn't compatible with just any type. You can create a Func<> that matches the method's return type with MakeGenericType.
Type funcType = typeof(Func<>).MakeGenericType(instanceMethod.ReturnType);
Delegate del = Delegate.CreateDelegate(funcType, null, instanceMethod);
As an aside, I'd name the method GetInstance instead of Instance, to make things clearer. (if it were a property, Instance would be appropriate)

Reflection of generic method not working

I have a generic static method which registers a interface and I need to write that using c# reflection.
Services.AddService<ITBroker>(new TBrokerService());
I tried following code but it is not working
Type[] externTBrokerService = Assembly.LoadFrom("Business.dll").GetTypes();
Type[] externService = Assembly.LoadFrom("ServiceModel.dll").GetTypes();
Type iTBroker = externITBroker[12];
MethodInfo method = externService[1].GetMethods()[2];
//Gets Add Service method
MethodInfo generic = method.MakeGenericMethod(iTBroker);
//Make method generic
generic.Invoke(null,new object[] { externTBrokerService[0]});
//invoke the service
Above code gives me very generic exception of parameters.
What is the write way to write reflection for above code?
As it was in comments:
Note that externTBrokerService[0] is a Type and not an instance of that type.
Having that I feel a need to include sense of other comments as part of my answer.
Type iTBroker = externITBroker[12];
this is wrong! And sooner or later this will fail to find your type as the order of types in this collection is undetermined and can change. You should do it like this:
Type iTBroker = externITBroker.Single(x => x.Name == "ITBroker");
This is far form foolproof so be sure that the condition gives you unique result.
or simply load that type directly by (assuming that this is the AssemblyQualifiedName of your type):
Type.GetType("Business.ITBroker, Business");
To find method on your type there is a method Type.GetMethod one of its overloads will be sufficient to find your method.
To create instance of your type that needs to be passed as argument you can use
Activator.CreateInstance(brokerServiceType);

Categories