Create generic Func from reflection - c#

I've specified type in a variable: Type hiddenType. I need to create a Func<T> delegate where T is of type specified in mentioned variable and assign an method:
var funcType = typeof(Func<>).MakeGenericType(hiddenType);
Func<object> funcImplementation = () => GetInstance(hiddenType);
var myFunc= Delegate.CreateDelegate(funcType , valueGenerator.Method);
It doesn't works - because funcImplementation is returns object instead of desired. At runtime, it will surely be an instance of type specified in hiddenType.
GetInstance returns object and signaure cannot be changed.

You can solve this by building an expression tree manually, and inserting a cast to hiddenType. This is allowed when you construct an expression tree.
var typeConst = Expression.Constant(hiddenType);
MethodInfo getInst = ... // <<== Use reflection here to get GetInstance info
var callGetInst = Expression.Call(getInst, typeConst);
var cast = Expression.Convert(callGetInst, hiddenType);
var del = Expression.Lambda(cast).Compile();
Note: the above code assumes that GetInstance is static. If it is not static, change the way you construct callGetInst to pass the object on which the method is invoked.

Instead of using a Type, you could consider using a generic wrapper, if it's not possible for you to change the GetInstance signature:
private Func<THidden> GetTypedInstance<THidden>()
{
return () => (THidden)GetInstance(typeof(THidden));
}
Then you can just call it with
GetTypedInstance<SomeClass>();
instead of
GetInstance(typeof(SomeClass));

Related

C# How to cast from Type without IConvertible using reflection

My returning value of the method CastTo is from the wrong type.
The method CastTo has a returning parameter < T >.
The commented line is what it does without using reflection
//FieldChoice ChoiceProduct = clientContext_temp.CastTo<FieldChoice>(field);
Type FieldChoiceType = sharepointClient.GetType("Microsoft.SharePoint.Client.FieldChoice");
object FieldChoice = Activator.CreateInstance(FieldChoiceType, sharepointClient, web.);
MethodInfo castToMethodInfo = typeclientContext.GetMethod("CastTo");
MethodInfo genericCastTo = castToMethodInfo.MakeGenericMethod(field.GetType());
var ChoiceProduct = genericCastTo.Invoke(clientContext, new object[] { field });
ChoiceProduct = Convert.ChangeType(ChoiceProduct, FieldChoiceType);
Choiceproduct is from the type Field but should be from the type FieldChoice.
The problem is, i can't create an instance of Fieldchoice before the method cause sharepoint just doesn't have a fittable constructor to allow creating it and i can't cast it to the Type with using Convert.changeType cause it doen't have a IConvertible implementation.
Is there any other way i can cast my variable or change the return type of the method?
I think that your problem is that you're passing field object to genericCastTo instead of FieldChoice.

How to invoke lambda method that is non-static using MethodInfo (uses <>c__DisplayClass1)

Consider the following code:
bool result;
Func<int, bool> lambda1 = i => i == 9000;
MethodInfo lambda1Method = lambda1.Method;
result = (bool)lambda1Method.Invoke(null, new object[] { 9000 }); // this works, result = true
int myLocalVariable = 9000;
Func<int, bool> lambda2 = i => i == myLocalVariable;
MethodInfo lambda2Method = lambda2.Method;
result = (bool)lambda2Method.Invoke(null, new object[] { 9000 }); // error
Invoking lambda2Method results in a System.Reflection.TargetException:
Non-static method requires a target.
This question here explains why the lambda1Method is static, while lambda2Method is non-static. Basically if lambdas contain local variables, a class is dynamically created that interprets each local variable as a field. lambda2Method becomes an instance method of that new class. I know this because lambda2Method.DeclaringType is <>c__DisplayClass1, and lambda2Method.IsStatic is false.
My question is, how can I make this work? I understand that because lambda2Method is non-static, I need to supply a value for the object obj parameter of MethodBase.Invoke(), and it needs to be an instance of <>c__DisplayClass1, but how do I obtain this instance?
The main issue that you need to address in you question is How to create an instance of a type generated by the compiler ?
So, if you really have to use MethodInfo, then you can create the required instance by using Reflection:
var instance = Activator.CreateInstance(lambda2Method.DeclaringType);
result = lambda2Method.Invoke(instance, new object[] { 9000 });
Summary:
The declaring type for your method lambda2 is a hidden class generated by the compiler. MethodInfo.Invoke requires a target instance of that type to invoke a non-static method.
Edit:
To get the captured value of myVariable correct, you can make use of the Target property :
result = lambda2Method.Invoke(lambda2.Target, new object[] { 9000 });

Converting lambda or method group to Action<T> where T is only known at runtime

I'm dynamically creating a type from a string passed to me at runtime.
I have the following code at the moment:
string messageType = "CustomerCreatedMessage";
//Convert the string to a Type
var type = Type.GetType(messageType);
//Create a Type of Action<CustomerCreatedMessage>
var action = typeof(Action<>).MakeGenericType(messageType);
How would I make a variable of the type of action and assign the lambda m=> SetActive(true) to it? I will then use the variable (named ??? here) in the following code:
//Create a generic method "Register" on my Messenger class that takes an Action<CustomerCreatedMessage> parameter.
var method = typeof(Messenger).GetMethod("Register");
var genericMethod = method.MakeGenericMethod(action);
//Invoke the created method with our script in it
genericMethod.Invoke(Messenger.Default, ???);
My goal is to be able to call my generic method Messenger.Default.Register<> with an Action<> that takes as type parameter a type created from my messageType string.
I have tried the following already:
Convert.ChangeType(m=>SetActive(true),action);
var filledAction = Activator.CreateInstance(action);
filledAction = m=>SetActive(true);
But both methods complain about converting a lambda expression to an object because it is not a delegate.
I get a similar error if I put SetActive(true) into a method and try to pass the method group.
Given that you're not using the parameter at all, I'd create a new generic method:
private static void GenericSetActive<T>(T ignored)
{
SetActive(true);
}
Then create a delegate using that:
var genericMethod = typeof(Foo).GetMethod("GenericSetActive",
BindingFlags.NonPublic |
BindingFlags.Static);
var concreteMethod = genericMethod.MakeGenericMethod(type);
var actionInstance = Delegate.CreateDelegate(action, concreteMethod);
Basically, you can't use a lambda expression here because you don't have a specific delegate type to convert it to.

convert class string to class

I have the code below in my ASP.NET app, I would like to convert converterName variable to
Class and pass it to FillRequest<T> method.
Is it possible?
var converterName = HttpContext.Current.Items["ConverterName"] as string;
FillRequest<Web2ImageEntity>(Request.Params);
Alternatively I could do
var converterName = HttpContext.Current.Items["ConverterName"] as string;
if (converterName == "Web2ImageEntity")
FillRequest<Web2ImageEntity>(Request.Params);
but I have about 20 entity classes and I would like to find a way to write code as short as possible.
That would not be possible as the generic type needs to be specified at the compile time.
What you can do is change the FillRequest method to be something like below and then use reflection to do the desired task
FillRequest(string[] params,Type converter)
{
//Create object from converter type and call the req method
}
Or make the FillRequest take a Interface
FillRequest(string[] params, IConverter c)
{
//call c methods to convert
}
Calling this would be something like:
var type = Type.GetType(converterName);
FillRequest(Request.Params,(IConverter)Activator.CreateInstance(type));
Yes, take a look at Activator.CreateInstance():
var converterName = HttpContext.Current.Items["ConverterName"] as string;
var type = Type.GetType(converterName);
var yourObject = Activator.CreateInstance(type);
Be aware that the type must have a public parameterless constructor. Here is a link to the MSDN documentation; there are a bunch of overloads which might be useful to you:
http://msdn.microsoft.com/en-us/library/system.activator.createinstance.aspx
UPDATE: If you must pass the object to a method with a generic type, then you will run into problems because the type is not known at compile time. In that case, I would consider having all of your converters implement a common interface, something like this:
var converterName = HttpContext.Current.Items["ConverterName"] as string;
var type = Type.GetType(converterName);
var yourObject = Activator.CreateInstance(type) as IMyConverter;
if (yourObject != null)
FillRequest<IMyConverter>(yourObject);
I found code idea here. Peter Moris pointed that he took code from Jon Skeets book, so if it will be useful - high five to Jon :)
create method:
public void DoFillRequest(Type type, string[] params)
{
MethodInfo methodInfo = this.GetType().GetMethod("FillRequest");
MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(new Type[]{ type });
genericMethodInfo.Invoke(this, new object[]{ params });
}
and now call it:
var type = Type.GetType(converterName);
DoFillRequest(type, Request.Params);

How do I get the return type of a delegate type through reflection?

I'm doing reflection-heavy work for a personal project, and I'd need to access the return type of a delegate through its Type object. This is a little meta, so here's an example.
Type type = typeof(Func<Foo, Bar, Baz>);
// ????
// Use reflection to come to the following expected result
Type result = typeof(Baz);
How can I do that?
I won't have any instance of that type to cast into Delegate.
One way would be to get a MethodInfo representing the delegate-type's Invoke method, and then retrieve the method's return type.
var result = type.GetMethod("Invoke").ReturnType;

Categories

Resources