none
DynamicMethod problem RRS feed

  • Question

  • Hi

    I've written and used DynamicMethods numerous times recently and this has all gone well. But now I have a situation that has me stumped. I want to create a dynamic method that accepts two args:

    a) A delegate (i.e. a method supplied by the caller of the dynamic method)
    b) An arg to be passed to the delegate.

    Therefore the dynamic method must be able to call the user supplied delegate and pass the arg to that delegate.

    Because the method to be called is not known at the time we gen the dynamic method, it looks as though we cant do this, because all variants of the Call opcode seem to require a method info to be defined and passed as we gen the dynamic method.

    Can anyone shed light on how to do this, or have I missed something obvious?

    Thanks

    Cap'n

     
    Saturday, March 6, 2010 3:16 PM

Answers

  • I believe the typically way to call a delegate would be through its Invoke method.  For example, this MSIL generated by C#:

    callvirt instance void WindowsFormsApplication.Form1/TestDelegate::Invoke(int32)

    However, when the delegate type is arbitrary, there is DynamicInvoke instead of Invoke.

    callvirt instance object [mscorlib]System.Delegate::DynamicInvoke(object[])

    Of course, this is going to affect performance.  This seems "obvious", but avoiding the performance hit is not.  I wouldn't rule out there being a slick way to avoid it by generating some MSIL on the fly, I'm just not too familiar with this area.

    OK I wrote some simple C# code that does the call and examined its IL. It seems to simply get at the "Invoke" method in the delegate type and then does a callvirt on the instance of the object that contains the target method (that the delegate itself has been set to).

    Here is the IL for the actual call operation (the details are simply the names etc I used for my test class, delegate etc, the actual delegate is generic and takes a ref to a struct and returns a bool, its args address is pushed by the previous line which I haven't bothered to include here)

      L_0040: callvirt instance bool IndexTesting.Tester/MyDelegate<valuetype IndexTesting.DataRecord>::Invoke(!0&)

    I am not clear though on the odd argument syntax to "Invoke" above, what does (!0&) mean?

    Thanks

    Cap'n


    Saturday, March 6, 2010 11:41 PM
  • Search the ECMA CLI spec:
      - & ... Interior managed pointer (I.12.1.1.2 "Managed pointer types: O and &")
      - !0 ... First generic parameter with index 0 (II.9 "Generics")

    You are right that in general the best way to find the right IL syntax is to write what you need in C#/VB and then look at the emitted IL code.

    -Karel
    Monday, March 8, 2010 12:41 AM
    Moderator

All replies

  • I believe the typically way to call a delegate would be through its Invoke method.  For example, this MSIL generated by C#:

    callvirt instance void WindowsFormsApplication.Form1/TestDelegate::Invoke(int32)

    However, when the delegate type is arbitrary, there is DynamicInvoke instead of Invoke.

    callvirt instance object [mscorlib]System.Delegate::DynamicInvoke(object[])

    Of course, this is going to affect performance.  This seems "obvious", but avoiding the performance hit is not.  I wouldn't rule out there being a slick way to avoid it by generating some MSIL on the fly, I'm just not too familiar with this area.
    Saturday, March 6, 2010 3:44 PM
  • I believe the typically way to call a delegate would be through its Invoke method.  For example, this MSIL generated by C#:

    callvirt instance void WindowsFormsApplication.Form1/TestDelegate::Invoke(int32)

    However, when the delegate type is arbitrary, there is DynamicInvoke instead of Invoke.

    callvirt instance object [mscorlib]System.Delegate::DynamicInvoke(object[])

    Of course, this is going to affect performance.  This seems "obvious", but avoiding the performance hit is not.  I wouldn't rule out there being a slick way to avoid it by generating some MSIL on the fly, I'm just not too familiar with this area.

    Yes this is proving very very tricky.

    I cant generate code to call the user delegate instance because we need to have a MethodInfo as part of the Emit.Call invocation. Only the dynamic method itself is in a position to do this because the delegate isn't known unti the dynamic method itself is invoked.

    So perhaps I need to code a dynamic method that:

    a) makes a call to GetMethodInfo on the delegate.
    b) calls the delegate using the MethodInfo and the delegates args.

    But in order to do a) the dynamic method needs a MethodInfo for the call to GetMethod.

    So I must gen code that makes a call to System.Type.GetMethod to get a MethodInfo for System.Type.GetMethod, then the dynamic method is able to call GetMethod itself, on the delegate.

    Does this sound workable or am I drifting into whichcraft...?

    Cap'n

    Saturday, March 6, 2010 9:27 PM
  • I believe the typically way to call a delegate would be through its Invoke method.  For example, this MSIL generated by C#:

    callvirt instance void WindowsFormsApplication.Form1/TestDelegate::Invoke(int32)

    However, when the delegate type is arbitrary, there is DynamicInvoke instead of Invoke.

    callvirt instance object [mscorlib]System.Delegate::DynamicInvoke(object[])

    Of course, this is going to affect performance.  This seems "obvious", but avoiding the performance hit is not.  I wouldn't rule out there being a slick way to avoid it by generating some MSIL on the fly, I'm just not too familiar with this area.

    OK I wrote some simple C# code that does the call and examined its IL. It seems to simply get at the "Invoke" method in the delegate type and then does a callvirt on the instance of the object that contains the target method (that the delegate itself has been set to).

    Here is the IL for the actual call operation (the details are simply the names etc I used for my test class, delegate etc, the actual delegate is generic and takes a ref to a struct and returns a bool, its args address is pushed by the previous line which I haven't bothered to include here)

      L_0040: callvirt instance bool IndexTesting.Tester/MyDelegate<valuetype IndexTesting.DataRecord>::Invoke(!0&)

    I am not clear though on the odd argument syntax to "Invoke" above, what does (!0&) mean?

    Thanks

    Cap'n


    Saturday, March 6, 2010 11:41 PM
  • Search the ECMA CLI spec:
      - & ... Interior managed pointer (I.12.1.1.2 "Managed pointer types: O and &")
      - !0 ... First generic parameter with index 0 (II.9 "Generics")

    You are right that in general the best way to find the right IL syntax is to write what you need in C#/VB and then look at the emitted IL code.

    -Karel
    Monday, March 8, 2010 12:41 AM
    Moderator