08-18-2015 09:52 AM
I have a .NET DLL written in F# which contains some CLR events.
While I can see a list of all events contained within a class in the DLL in the Reg Event Callback function, the events never cause the callback VI to be called.
I have written an example in C# where everything works fine (even with .NET 4.6). If I write the same functionality in F#, the events never appear to be received in LabView. With F# I have tried with .NET version 3.0-4.6.
What on earth could be the cause of this?
08-18-2015 02:37 PM
@kasperh wrote:
I have a .NET DLL written in F# which contains some CLR events.
While I can see a list of all events contained within a class in the DLL in the Reg Event Callback function, the events never cause the callback VI to be called.
I have written an example in C# where everything works fine (even with .NET 4.6). If I write the same functionality in F#, the events never appear to be received in LabView. With F# I have tried with .NET version 3.0-4.6.
What on earth could be the cause of this?
I am assuming that F# compiles the events to IL using add_* and remove_* methods to a private delegate and labels the methods with metadata describing them as an event. This is what the C# compiler does and I presume that F# "events" compile the same although I have never tried this.
Can you post your examples in C# and F#?
08-19-2015 02:16 AM
Sure. The [<CLIEvent>] attribute instructs the compiler to use the add_ and remove_.
The F# I have used
namespace LabViewEventTest.FSharp type FSharpClass() = let someEvent = new Event<string>() [<CLIEvent>] member this.SomethingHappened = someEvent.Publish member this.ActionThatCausesEvent() = someEvent.Trigger("Something happened in F#")
The C#
namespace LabViewEventTest { public class CSharpClass { public event EventHandler<string> SomethingHappened; public void ActionThatCausesEvent() { SomethingHappened?.Invoke(this, "Something happened in C#"); } } }
08-19-2015 02:33 PM
@kasperh wrote:
Sure. The [<CLIEvent>] attribute instructs the compiler to use the add_ and remove_.
The F# I have used
namespace LabViewEventTest.FSharp type FSharpClass() = let someEvent = new Event<string>() [<CLIEvent>] member this.SomethingHappened = someEvent.Publish member this.ActionThatCausesEvent() = someEvent.Trigger("Something happened in F#")The C#
namespace LabViewEventTest { public class CSharpClass { public event EventHandler<string> SomethingHappened; public void ActionThatCausesEvent() { SomethingHappened?.Invoke(this, "Something happened in C#"); } } }
Interesting. Presumably the metadata is intact; the CTS defines events and the event structure so I would be suprised if F# did not comply with this. Have you compared the IL?
08-20-2015 02:56 AM
The IL produced by F# and C#:
FSharpClass.add_SomethingHappened
IL_0000: nop IL_0001: ldarg.0 IL_0002: ldfld Query_zfrpxs+FSharpClass.someEvent IL_0007: callvirt Microsoft.FSharp.Control.FSharpEvent<System.String>.get_Publish IL_000C: ldarg.1 IL_000D: tail. IL_000F: callvirt Microsoft.FSharp.Control.IDelegateEvent<Microsoft.FSharp.Control.FSharpHandler<System.String>>.AddHandler IL_0014: ret
CSharpClass.add_SomethingHappened:
IL_0000: ldarg.0 IL_0001: ldfld UserQuery+Class1.SomethingHappened IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: stloc.1 IL_0009: ldloc.1 IL_000A: ldarg.1 IL_000B: call System.Delegate.Combine IL_0010: castclass System.EventHandler<System.String> IL_0015: stloc.2 IL_0016: ldarg.0 IL_0017: ldflda UserQuery+Class1.SomethingHappened IL_001C: ldloc.2 IL_001D: ldloc.1 IL_001E: call System.Threading.Interlocked.CompareExchange IL_0023: stloc.0 IL_0024: ldloc.0 IL_0025: ldloc.1 IL_0026: ceq IL_0028: ldc.i4.0 IL_0029: ceq IL_002B: stloc.3 IL_002C: ldloc.3 IL_002D: brtrue.s IL_0007 IL_002F: ret
But F# does indeed generate the add_ function.
08-20-2015 01:59 PM
What about the metadata tags information for both methods?
08-20-2015 03:03 PM
For F#:
Method #2 (06000002) ------------------------------------------------------- MethodName: add_SomethingHappened (06000002) Flags : [Public] [HideBySig] [ReuseSlot] [SpecialName] (00000886) RVA : 0x00002068 ImplFlags : [IL] [Managed] (00000000) CallCnvntn: [DEFAULT] hasThis ReturnType: Void 1 Arguments Argument #1: GenericInst Class Microsoft.FSharp.Control.FSharpHandler`1< String> 1 Parameters (1) ParamToken : (08000001) Name : handler flags: [none] (00000000)
And C#:
Method #1 (06000001) ------------------------------------------------------- MethodName: add_SomethingHappened (06000001) Flags : [Public] [HideBySig] [ReuseSlot] [SpecialName] (00000886) RVA : 0x00002050 ImplFlags : [IL] [Managed] (00000000) CallCnvntn: [DEFAULT] hasThis ReturnType: Void 1 Arguments Argument #1: GenericInst Class System.EventHandler`1< String> 1 Parameters (1) ParamToken : (08000001) Name : value flags: [none] (00000000) CustomAttribute #1 (0c000001) ------------------------------------------------------- CustomAttribute Type: 0a00000f CustomAttributeName: System.Runtime.CompilerServices.CompilerGeneratedAttribute :: instance void .ctor() Length: 4 Value : 01 00 00 00 > < ctor args: ()
08-20-2015 03:20 PM
Rather than asking a bunch more questions, check out the metadata for the assembly, in particular the tables, for the following: http://flylib.com/books/en/2.663.1.93/1/. Hopefully the content should line up.
08-24-2015 03:20 AM
I have now looked at the two sets of metadata, and I don't see any particular difference in what they describe. I wouldn't expect there to be, as the events work fine outside LabVIEW.
08-26-2015 05:50 AM
I have fixed this now.
It appears that for the event to work properly in LabVIEW it's necessary to use an custom delegate (or the EventHandler delegate).
let someEvent = new Event<EventHandler<string>, string>()