Search code examples
c#delegates

Function pointer on generic class delegate


I need to get a FunctionPointerForDelegate to pass a native P/Invoke, but the function resides in a generic class of type myClass

When I try to create the Pointer I get an error of

System.ArgumentException: 'The specified Type must not be a generic type. (Parameter 'delegate')'

Is there any workaround to this?

var c = new MyClass<int>();
c.DoWork();

public class MyClass<T> {

    private protected delegate int MyCompareCallback(int idxA, int idxB);

    private int SortCompareFunction(int idxA, int idxB) {
        return -1; // simplified implementation
    }

    public void DoWork() {
        MyCompareCallback SortCallback = new(SortCompareFunction);
        IntPtr callbackPtr = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(SortCallback);
        Console.WriteLine("Success"); // Fails on previous line with System.ArgumentException: 'The specified Type must not be a generic type. (Parameter 'delegate')'
    }

}


Solution

  • You need to consider that your delegate type MyCompareCallback is actually MyClass<T>.MyCompareCallback. It is a generic type.

    When you read the documentation for Marshal.GetFunctionPointerForDelegate it specifically says the System.ArgumentException will be thrown if the delegate is a generic type.

    You really have two choices.

    (1) remove the generic type parameter from MyClass

    public class MyClass
    {
        private protected delegate int MyCompareCallback(int idxA, int idxB);
        private int SortCompareFunction(int idxA, int idxB) => -1;
        public void DoWork()
        {
            MyCompareCallback SortCallback = new MyCompareCallback(SortCompareFunction);
            IntPtr callbackPtr = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(SortCallback);
            Console.WriteLine("Success");
        }
    }
    

    (2) move the delegate outside of MyClass<T>

    internal delegate int MyCompareCallback(int idxA, int idxB);
    public class MyClass<T>
    {
        private int SortCompareFunction(int idxA, int idxB) => -1;
        public void DoWork()
        {
            MyCompareCallback SortCallback = new MyCompareCallback(SortCompareFunction);
            IntPtr callbackPtr = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(SortCallback);
            Console.WriteLine("Success");
        }
    }