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.
Related
I want to check if an anonymous function has been called with NSubstitute. A method in a class I have takes a Func<> parameter, and I want to make sure this parameter is called (or not called). I have tried the following, but it does not seem to work:
var spy = Substitute.For<Func<string, int>>();
MyClass.DoSomething(spy);
spy.Invoke(Arg.Any<string>()).Received();
This however throws an exception:
NSubstitute.Exceptions.NullSubstituteReferenceException : NSubstitute extension methods like .Received can only be called on objects created using Substitute.For<T>() and related methods.
Try replacing
spy.Invoke(Arg.Any<string>()).Received();
with
spy.Received().Invoke(Arg.Any<string>());
There's no difference if your production code calls the func via spy.Invoke() or via spy(). But the test won't succeed, if your code calls BeginInvoke. But I think that shouldn't be a problem, because you should know in advance if a test for Invoke or BeginInvoke is needed.
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.
I've always thought that it's impossible for this to be null inside instance method body. Following simple program demonstrates that it is possible. Is this some documented behaviour?
class Foo
{
public void Bar()
{
Debug.Assert(this == null);
}
}
public static void Test()
{
var action = (Action)Delegate.CreateDelegate(typeof (Action), null, typeof(Foo).GetMethod("Bar"));
action();
}
UPDATE
I agree with the answers saying that it's how this method is documented. However, I don't really understand this behaviour. Especially because it's not how C# is designed.
We had gotten a report from somebody (likely one of the .NET groups
using C# (thought it wasn't yet named C# at that time)) who had
written code that called a method on a null pointer, but they didn’t
get an exception because the method didn’t access any fields (ie
“this” was null, but nothing in the method used it). That method then
called another method which did use the this point and threw an
exception, and a bit of head-scratching ensued. After they figured it
out, they sent us a note about it.
We thought that being able to call a method on a null instance was a
bit weird. Peter Golde did some testing to see what the perf impact
was of always using callvirt, and it was small enough that we decided
to make the change.
http://blogs.msdn.com/b/ericgu/archive/2008/07/02/why-does-c-always-use-callvirt.aspx
Because you're passing null into the firstArgument of Delegate.CreateDelegate
So you're calling an instance method on a null object.
http://msdn.microsoft.com/en-us/library/74x8f551.aspx
If firstArgument is a null reference and method is an instance method,
the result depends on the signatures of the delegate type type and of
method:
If the signature of type explicitly includes the hidden first
parameter of method, the delegate is said to represent an open
instance method. When the delegate is invoked, the first argument in
the argument list is passed to the hidden instance parameter of
method.
If the signatures of method and type match (that is, all parameter
types are compatible), then the delegate is said to be closed over a
null reference. Invoking the delegate is like calling an instance
method on a null instance, which is not a particularly useful thing to
do.
Sure you can call into a method if you are using the call IL instruction or the delegate approach. You will set this booby trap only off if you try to access member fields which will give you the NullReferenceException you did seek for.
try
int x;
public void Bar()
{
x = 1; // NullRefException
Debug.Assert(this == null);
}
The BCL does even contain explicit this == null checks to aid debugging for languages which do not use callvirt (like C#) all the time. See this question for further infos.
The String class for example has such checks. There is nothing mysterious about them except that you will not see the need for them in languages like C#.
// Determines whether two strings match.
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public override bool Equals(Object obj)
{
//this is necessary to guard against reverse-pinvokes and
//other callers who do not use the callvirt instruction
if (this == null)
throw new NullReferenceException();
String str = obj as String;
if (str == null)
return false;
if (Object.ReferenceEquals(this, obj))
return true;
return EqualsHelper(this, str);
}
Try the documentation for Delegate.CreateDelegate() at msdn.
You're "manually" calling everything, and thus instead of passing an instance in for the this pointer, you're passing null. So it can happen, but you have to try really really hard.
this is a reference, so there is no problem with its being null from the perspective of the type system.
You may ask why NullReferenceException was not thrown. The full list of circumstances when CLR throws that exception is documented. Your case is not listed. Yes, it is a callvirt, but to Delegate.Invoke (see here) rather than to Bar, and so the this reference is actually your non-null delegate!
The behavior you see has an interesting implementational consequence for CLR. A delegate has a Target property (corresponds to your this reference) that is quite frequently null, namely when the delegate is static (imagine Bar be static). Now there is, naturally, a private backing field for the property, called _target. Does _target contain a null for a static delegate? No it doesn't. It contains a reference to the delegate itself. Why not null? Because a null is a legitimate target of a delegate as your example shows and CLR does not have two flavors of a null pointer to distinguish the static delegate somehow.
This bit of trivium demonstrates that with delegates, null targets of instance methods are no afterthought. You may still be asking the ultimate question: but why they had to be supported?
The early CLR had an ambitious plan of becoming, among others, the platform of choice even for sworn C++ developers, a goal that was approached first with Managed C++ and then with C++/CLI. Some too challenging language features were omitten, but there was nothing really challenging about supporting instance methods executing without an instance, which is perfectly normal in C++. Including delegate support.
The ultimate answer therefore is: because C# and CLR are two different worlds.
More good reading and even better reading to show the design allowing null instances shows its traces even in very natural C# syntactic contexts.
this is a readonly reference in C# classes. Accordingly and as expected this can be used like any other references (in read only mode) ...
this == null // readonly - possible
this = new this() // write - not possible
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.
I'm working on a CRUD testing class because I got tired of duplicating the same test patterns when validating my NHibernate mappings.
I've refactored the code and have reached the point where everything is working the way I envisioned it with one glaring irritation. Everything is based on strings which are used by reflection methods to call the appropriate repository methods and get the values of the corresponding properties like entity Id's.
This works but I'm sure I don't need to go into the evils of using strings for such things.
So I started to work with Linq. I'm not a heavy Linq user and the following code has me utterly baffled.
It works almost perfectly (I'll get to the almost in a second) and I'm very happy it works but I would really love to know why.
[Test]
public void TestCanUseTesterWithLinqSecondEffort()
{
IRepositoryTestContextManager contextManager = new NHRepositoryTestContextManager();
contextManager.SetUpRepositoryContextAndSchema();
TestInsertMethodWithLinq<NHClientRepository, Client>((x, y) => x.InsertClient(y), _newClient);
contextManager.ResetRepositoryContext();
Client retrievedClient = TestRetrieveMethodWithLinq<NHClientRepository, Client, string>((clientRepository, publicId) => clientRepository.GetClient(publicId), client => client.PublicId, _newClient);
contextManager.TearDownRepositoryContext();
Assert.IsNotNull(retrievedClient);
Assert.AreNotSame(_newClient, retrievedClient);
Assert.AreEqual(_newClient.Id, retrievedClient.Id);
Assert.AreEqual(_newClient.PublicId, retrievedClient.PublicId);
Assert.AreEqual(_newClient.Name, retrievedClient.Name);
}
private void TestInsertMethodWithLinq<TRepositoryType, TEntityType>(Action<TRepositoryType, TEntityType> insertMethod, TEntityType entity)
where TRepositoryType : class, new()
{
insertMethod.Invoke(new TRepositoryType(), entity);
}
private TEntityType TestRetrieveMethodWithLinq<TRepositoryType, TEntityType, TArgumentType>(Func<TRepositoryType, TArgumentType, TEntityType> retrieveMethod, Func<TEntityType, TArgumentType> paramValue, TEntityType theEntity)
where TRepositoryType : class, new()
{
return retrieveMethod.Invoke(new TRepositoryType(), paramValue(theEntity));
}
Specifically I'm talking about the two invoked delegates (I know one does not have to call invoke to use the delegate. I included it for clarification). How does the compiler transform the Linq expressions so that the correct methods are called on a newly instantiated class, in this case the TRepositoryTypes?
Regarding the almost in "almost perfectly", if there is an exception during the processing of the invoked method, the exception is swallowed. Don't know why that is either but I can already see a scenario where the tests are not complete and a problem is missed because the exceptions are swallowed.
Chew on that. Thanks in advance.
How does the compiler transform the Linq expressions so that the correct methods are called on a newly instantiated class, in this case the TRepositoryTypes?
They're not actually Linq expressions (Expression<T>), just regular ol' lambdas.
The compiler just creates an "anonymous" method, in an "anonymous" class to capture any variables. In this case, you have no captured variables - so this:
TestInsertMethodWithLinq<NHClientRepository, Client>(
(x, y) => x.InsertClient(y), _newClient
);
simply gets transformed to an "anonymous" method:
class __abcde {
public void __fghij(NHClientRepository x, Client y) {
x.InsertClient(y);
}
}
with the caller being transformed to:
var c = new __abcde();
c.__fghij(new NHClientRepository(), _newClient);
Since your generic constraint required a new() no-args constructor, the compiler was able to insert that new NHClientRepository() bit.
I'm not an NHibernate user (or any other ORM for that matter), so I can only speculate. But I suspect what's going on here is that you're using a closure. When you create a closure, the variable you use in the lambda expression is captured/closed-over/hoisted into a class along with the method, so that the value stays current even if you don't invoke the method until much later.
I might have missed something, but I believe your referring to generics and polymorphism.
You want a TRepository type passed in, and to call a method that all TRepository types can call. The magic happens here:
TestInsertMethodWithLinq<NHClientRepository, Client>((x, y) => x.InsertClient(y), _newClient);
You're stating that I'm going to call this method and use the type NHClientRepository and Client. You then make the function call and the generic method will use NHClient in this line:
insertMethod.Invoke(new TRepositoryType(), entity);
This will resolve TRepositoryType() to be an NHClientRepository. The method then invokes using the type and the action that you passed in, giving you your result.
You might want to put a break point on your test and stepping through with the debugger while watching the call stack if you want to try and follow whats happening, you can look at all the generic types and method calls etc to help you understand whats going on.
EDIT: In reference to your comment, the C# 3 type inference is helping you out with the action. Type inference is what maps x and y to be NHClientRepository and Client, which then allows the call to work. As the compiler knows at compile time what you are performing it is able to assist you with this. You should be able to see that intellisense is able to help you out if you were to call the insertMethod without invoking.
I'm assuming that was the final piece of the puzzle for you?