Search code examples
f#byref

[F#][sharppcap][Error] "A type instantiation involves a byref type." what is a workaround in F#


I try to use SharpPcap in F#, but I was blocked by this compiler error for two days.

I find the most releate answer is What is the error "A type instantiation involves a byref type." and what is a workaround in F#, but do not fit my context well.

Please help me work around it, Thank you!

open System
open SharpPcap
open SharpPcap.LibPcap

let device = new CaptureFileReaderDevice("test.pcap")

// try workaround 1
let new_package (sender: Object) (e: PacketCapture) = ()
let handler = new PacketArrivalEventHandler(new_package)
device.OnPacketArrival.AddHandler(handler)
// error: A type instantiation involves a byref type. This is not permitted by the rules of Common IL.

// try workaround 2
let new_package (e: PacketCapture) = ()
device.OnPacketArrival.Add(new_package)
// error: A type instantiation involves a byref type. This is not permitted by the rules of Common IL.

I think the error is because:

public event PacketArrivalEventHandler OnPacketArrival;
public delegate void PacketArrivalEventHandler(object sender, PacketCapture e);
public readonly ref struct PacketCapture
{...}

The delegate PacketArrivalEventHandler use PacketCapture as param type, but this is a readonly ref struct which can not use to define F# function to add to Event OnPacketArrival.

Pls help me workaround it, Thank you!

I want make this line pass the F# compiler:

device.OnPacketArrival.Add(new_package)

In c# it used in this way:

device.OnPacketArrival += new_package

[FS0412] A type instantiation involves a byref type. This is not permitted by the rules of Common IL.


Solution

  • You can't do this by using the F# IEvent first-class listening points, because in this case the type of device.OnPacketArrival ends up being IEvent<PacketArrivalEventHandler, ref<PacketCapture>>, whose second type parameter ref<PacketCapture> is not allowed. This is what the error message tells you.

    But you can use the underlying .NET add_ and remove_ methods, which are analogs of property get_ and set_ methods, but for events. F# allows you to call these "hidden" methods explicitly, even though they're not listed in IDE completion lists.

    device.add_OnPacketArrival handler
    

    It works, because it's directly calling a method on the device object, rather than creating a wrapping value of type IEvent<...> and then calling .Add or .AddHandler on it.