Using "Method" MethodInfo property from an Action<T> delegate in il.EmitCall - c#

Is something like this possible?
//
// create a delegate
Action<Type> action = (t) => t.DoSomething;
//
// get the IL generator for a method
ILGenerator il = myMethodBuilder.GetILGenerator();
//
// try and call the delegate
il.EmitCall(OpCodes.Callvirt, action.Method, null);
Im getting a MethodAccessException whenever I try to invoke the method.
Thanks

Im getting a MethodAccessException whenever I try to invoke the method.
This is because the method generated for the C# (t) => t.DoSomething lambda is private. Chances are this lambda won't be static, either, depending on which of the local variables it captures from the outer method. You're issuing a callvirt instruction but you don't appear to be supplying an instance.
You can verify this by loading your application's code in Reflector and looking at the implementation of your (t) => t.DoSomething lambda.
You need to either:
Upgrade your lambda to a real public static method in an externally-visible class
Find a way to include a parameter of type Action<Type> in your IL method, generate code that calls Action<Type>.Invoke, then pass your action variable into the generated method

See if this is related to what is mention Here.

If you use a dynamic method you can use the skip visibility checks in the jitter.

Related

Chained methods reflection execution

I need to execute some chained methods using reflection.
What I´m trying to get is an IQueryable of a Entity Core DBContext Set of an unknown compile type:
var type = typeof(x);
this.DBContext.Set(type).AsQueryable();
Obviously, that code does not compile because Set is a generic Method where the type must be defined in compile time:
this.DBContext.Set<TUnknownType>().AsQueryable();
To solve that, I tried to execute the methods using reflection:
MethodInfo dbSetMethod = typeof(DbContext).GetMethod(nameof(DbContext.Set));
MethodInfo generic = dbSetMethod.MakeGenericMethod(property.DeclaringType);
var asQueryableMethod = generic.ReturnType.GetMethod("AsQueryable");
var result = asQueryableMethod.Invoke(this.DbContext, null);
But when I debug the code, I get a null in the line:
var asQueryableMethod = generic.ReturnType.GetMethod("AsQueryable");
Apparently, the dbContext.Set<TUnknownType>() does not have the AsQueryable method. That method is an extension method coming from Linq I guess.
What am I missing? Why is the method unavailable?
That's right, DbSet<T> implements IQueryable<T>, which exposes AsQueryable<T>() extension method.
C# offers two ways to invoke an extension method - as an instance method, i.e.
this.DBContext.Set<UnknownType>().AsQueryable();
or as a static method, i.e.
Queryable.AsQueryable(this.DBContext.Set<UnknownType>());
Reflection APIs, on the other hand, support only the second approach, i.e. the static method way of obtaining and invoking the method. You should get MethodInfo for generic Queryable.AsQueryable, and pass it an appropriate generic type parameter to make a MethodInfo object suitable for invocation.

Get the token of a closed uncreated generic method

I'm using MethodBuilder.SetMethodBody() to emit the method instead of using the built in ILGenerator. The reason is mainly more control with exception handling information, and generally to have more control over the opcodes emitted.
In all situations where I need to emit a call to a method I'm calling ModuleBuilder.GetMethodToken() and it works fine except for when I need to call a closed generic method that is uncreated (withing the same dynamic module). It's throwing a NotSupportedException:Specified method is not supported..
Of course MethodBuilder.TokenMetadata doesn't work because the method is uncreated, and this leaves me with nothing else to try.
So the question is, how do I get the token to use in my custom emitting of a call opcode to this generic method?
Edit: I found out that the built in ILGenerator.EmitCall gets the token through a call to an internal method that accepts a bool, the generator passes false sometimes. However, MethodBuilder.GetMethodToken() always passes true to the same internal method. It seems to be it, but since internal methods are out of my reach, there has to be another way?
I'm actually thinking about using reflection to get and invoke the method manually if there's no other way.
Edit: Indeed, invoking the internal method (which is ModuleBuilder.GetMethodTokenInternal btw) through reflection with false as a parameter does solve the issue. But I don't believe that there isn't a normal way of getting the token, since the SetMethodBody needs it if you manually call to a generic method.
The solution I came up with is invoking the internal method through reflection and pass it the required args.
// If the to be called method is generic...
var methodInfo = Type.GetType("System.Reflection.Emit.ModuleBuilder")
.GetTypeInfo()
.DeclaredMethods
.Where((method) => method.Name == "GetMethodTokenInternal" && method.GetParameters().Length == 3)
.First();
int token =
(int)methodInfo.Invoke(_moduleBuilder, new object[] { closedGenericMethod, null, false });
But I actually use a delegate to make things faster after the first call.

How to Dynamically Create Method from String for Lambda Expression

My ultimate goal is to create a function that will dynamically pass method names to classes in the Hangfire library.
For example, here is the non-dynamic code which works:
RecurringJob.AddOrUpdate(() => myFunction(), Cron.Hourly)
The type of the first argument for AddOrUpdate is Expression<Action>. My first step was to use reflection to dynamically insert the function name:
Type thisControllerType = this.GetType();
MethodInfo method = thisControllerType.GetMethod(methodName); //methodName passed as string parameter
RecurringJob.AddOrUpdate(() => method.Invoke(this, null), Cron.Hourly);
When I check the Hangfire dashboard, it seems that this expression is being evaluated as MethodBase.Invoke. So I need help passing in the method name dynamically.
That may be enough info to answer my question, but another path I have taken is trying to generate the entire expression for the argument.
RecurringJob.AddOrUpdate(CreateCallExpression(method), Cron.Hourly);
public Expression<Action> CreateCallExpression(MethodInfo method)
{
//trying to pass in zero argument parameter, not sure if this syntax is correct
var parameter = System.Linq.Expressions.Expression.Parameter(typeof (Array));
return System.Linq.Expressions.Expression.Lambda<Action>(System.Linq.Expressions.Expression.Call(method, parameter));
}
In this case I am getting the exception {"Static method requires null instance, non-static method requires non-null instance.\r\nParameter name: method"}. I am working on that, but not sure if this is the road I should be going down. I have been working on this all day, so I was hoping someone might be able to help me speed up my learning.
Your second instance will work in creating a pointer to your specified method, but to solve your static issue you just need to modify the following line in one of 2 ways. First you can complete the static reference by declaring the method you seek to be static and modifying this line of code:
System.Linq.Expressions.Expression.Call(method, parameter);
You would have to provide a null parameter for the call method because if you are searching for a static method, then the compiler will know exactly what method signature you desire, because there will only exist 1. The line of code would be updated to:
System.Linq.Expressions.Expression.Call(null, method, parameter);
The second approach is to define the class or "instance" that correlates to the method so that the compiler knows what class to search against for the method signature. You would have to modify your code like this:
var myInstance = Expression.Parameter(typeof(MyClass), "inst");
System.Linq.Expressions.Expression.Call(myInstance, method, parameter)
I recommend looking at the documentation for Call so that you know exactly how the pointer is being created.

dynamic method invocation in expression tree

When constructing an expression tree, I have to use nodes invoking external methods in order to obtain values the expression could then continue evaluation with.
These methods are supplied as Func<T> and my code has no knowledge of where they originate from.
What is the most correct way of performing the mentioned invocation? I've tried something like this:
private Dictionary<string, Delegate> _externalSymbols;
private Expression _forExternalSymbol(string identifier)
{
Delegate method = _externalSymbols[identifier];
return Expression.Call(method.Method);
}
which works as long as the method fetched from the dictionary was created in compile-time. However, in case of Func<T> being a dynamic method obtained, for instance, by compiling another expression in runtime, this won't work out throwing
ArgumentException: Incorrect number of arguments supplied for call to method 'Int32 lambda_method(System.Runtime.CompilerServices.ExecutionScope)'
The desired effect may be achieved by wrapping the given function into one extra expression, but that seems quite hideous comparing to what it used to look like:
private Expression _forExternalSymbol(string identifier)
{
Delegate method = _externalSymbols[identifier];
Expression mediator = method is Func<double> ?
(Expression)(Expression<Func<double>>)(() => ((Func<double>)method)()) :
(Expression<Func<string>>)(() => ((Func<string>)method)());
return Expression.Invoke(mediator);
}
Also, this is hardly an extensible approach should I need to add support for types other than double and string.
I would like to know if there are better options which would work with dynamically created methods (preferably applicable to .NET 3.5).
which works as long as the method fetched from the dictionary was created in compile-time
No, it works as long as the method is static. For example, it also won't work if the delegate is a lambda that references something from its parent score (i.e. it's a closure).
The correct way to invoke a delegate is to use Expression.Invoke(). To get an Expression that represents your delegate, use Expression.Constant():
Expression.Invoke(Expression.Constant(method)))

C# - Is it possible to get the owner type of a method from an Action?

I have a class that implements an Interface with some methods.
I also have method with an Action parameter where I pass the Interface method.
Is it possible to get the type of the owner that has the method?
EDIT
This is the wrapper:
private void Wrapper (params Action[] actions)
{
var action = actions.FirstOrDefault();
var type = action.Method.DeclaringType.Name;
}
private void test()
{
Wrapper(()=> _GC.ChargeCancellation(""));
}
For demonstration purpose I don't iterate through the collection.
I want the type of _GC.
Actually, I should've spotted this to begin with but since Jon didn't either I'm not feeling too bad about it :)
The code you have to begin with in your question does not compile:
Wrapper(() => TestClass.Hello);
This is not complete code. You either have to have:
Wrapper(TestClass.Hello);
^
|
+-- notice the missing () => here
or:
Wrapper(() => TestClass.Hello());
^
|
+-- notice the added parenthesis here
And now that you have edited your question, it is clear you have the second form.
There's a subtle difference between the two. Subtle to us, but important to the compiler:
Wrapper(TestClass.Hello);
^------+------^
|
+-- This is a method group
Wrapper(() => TestClass.Hello());
^------+--------^
|
+-- This is a method call
A method group is a reference to a method (or its overloads), a method call is executable code.
The difference to the compiler is that in the first piece of code, the compiler will wrap up the method group into an action, basically compile it like this:
Wrapper(new Action(TestClass.Hello));
and thus, you're passing that method to the Wrapper method, inside an Action delegate.
However, the second form is handled altogether differently. The compiler now produces a new method to contain your code, and then passes the new method to the Wrapper method instead of the code you had.
Thus, your code actually looks like this:
public static void Main()
{
Wrapper(new Action(TempMethod1));
}
private static void TempMethod1()
{
TestClass.Hello();
}
And that's why you're seeing the form class as the owner of the method, because that's what it is.
The reason I asked in a comment whether you were taking a delegate or an expression is that my brain was working at half speed. It detected something odd, but not the whole picture.
If you want to pass code like this to a method, and work with it, you have two choices:
For a delegate, work with reflection, decompile the code and analyze it, find the method call and figure out which class it is made on
For an expression, analyze the pieces of the expression (this requires C# 3 or above)
Since neither is trivial I'm not going to post any code here, suffice to say that what you're asking warrants a new question. Of the two, I suggest you go with the expression way if you can.
EDIT: I misread the example, and thought it was using a method group conversion. You can certainly get the method in the delegate itself:
public void Wrapper(Action action)
{
MethodInfo method = action.Method;
Type type = method.DeclaringType; // TestClass
string name = method.Name; // Hello
}
I'm not sure off the top of my head which method will be used if you pass in a delegate instance with multiple actions... but it shouldn't be a problem in this case.
Doh - I misread the question. When you use a lambda expression, that's going to build an extra method in the calling class - and that is the method which contains the reference to _GC.
If you don't want this behaviour, you should change Wrapper to accept params Expression<Action>[] actions - you can then examine the expression trees appropriately and find out the calls that way. It's a bit fiddly sometimes, but it's doable. Look at the Body of the expression tree, which will represent the method call. Note that if you still want to execute the actions, you can call Compile on the expression tree to obtain a delegate.

Categories

Resources