How to implement a C# delegate containing an in-struct parameter in VB.NET?

Sjoerd van Kreel

Given the following delegate definition in C#:

struct Dummy {}
delegate int ReceiveDummy(in Dummy dummy);

How can I assign a a VB.Net sub to the ReceiveDummy type? Both the following function definitions fail with error BC30657: "has a return type that is not supported or parameter types that are not supported".

Shared Function MyReceiveDummy(ByVal dummy As Dummy) As Integer
Shared Function MyReceiveDummy(ByRef dummy As Dummy) As Integer
Dim receive As ReceiveDummy = New ReceiveDummy(AddressOf MyReceiveDummy)

Is there a VB.NET equivalent to C#'s "in" keyword?

dbc

This is extremely hacky, but it turns out to be possible (in .NET 7) to use Delegate.CreateDelegate() to create a delegate of a type with an in parameter from a static method whose signature actually accepts a ref parameter.

E.g. if I create (in C#):

struct Dummy {}
delegate int ReceiveDummy(in Dummy dummy);

static class DummyActions
{
    //https://github.com/dotnet/csharplang/blob/main/proposals/csharp-7.2/readonly-ref.md#metadata-representation-of-in-parameters
    static int ActuallyReceiveDummy(ref Dummy dummy)
    {
        return dummy.GetHashCode();
    }
    
    public static ReceiveDummy CreateReceiveDummy()
    {
        return (ReceiveDummy)
            Delegate.CreateDelegate(typeof(ReceiveDummy), 
                                    typeof(DummyActions).GetMethod(nameof(DummyActions.ActuallyReceiveDummy), 
                                                                   BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
    }
}

I can do:

var receiveMethod = DummyActions.CreateReceiveDummy();
Console.WriteLine(receiveMethod(new Dummy()));

An it works! Demo #1 here.

Translating to VB.NET, I get the following:

Friend Class DummyActions
    ' https://github.com/dotnet/csharplang/blob/main/proposals/csharp-7.2/readonly-ref.md#metadata-representation-of-in-parameters
    Private Shared Function ActuallyReceiveDummy(ByRef dummy As Dummy) As Integer
        ' Do whatever you want here but don't modify dummy!
        Return dummy.GetHashCode() 
    End Function

    Public Shared Function CreateReceiveDummy() As ReceiveDummy
        Return CType([Delegate].CreateDelegate(GetType(ReceiveDummy), 
            GetType(DummyActions).GetMethod(NameOf(DummyActions.ActuallyReceiveDummy), 
                BindingFlags.Static Or BindingFlags.Public Or BindingFlags.NonPublic)), ReceiveDummy)
    End Function
End Class

Which makes the following possible in VB.NET:

Dim receiveMethod = DummyActions.CreateReceiveDummy()
Console.WriteLine(receiveMethod(New Dummy()))

Mockup fiddle #2 here

Notes:

  • According to the design documents for in in C# 7.2

    When System.Runtime.CompilerServices.IsReadOnlyAttribute is applied to a byref parameter, it means that the parameter is an in parameter.

    In addition, if the method is abstract or virtual, then the signature of such parameters (and only such parameters) must have modreq[System.Runtime.InteropServices.InAttribute].

    Motivation: this is done to ensure that in a case of method overriding/implementing the in parameters match.

    Same requirements apply to Invoke methods in delegates.

    Motivation: this is to ensure that existing compilers cannot simply ignore readonly when creating or assigning delegates.

    It turns out that in C# the compiler will not allow you to manually apply IsReadOnlyAttribute, if you try you will get a compiler error Do not use 'System.Runtime.CompilerServices.IsReadOnlyAttribute'. This is reserved for compiler usage. (demo #3 here). But the VB.NET compiler makes no such restriction, so if you want to "future-proof" your method against some possible future version of Delegate.CreateDelegate() that checks for this attribute, you could add it manually:

    ' https://github.com/dotnet/csharplang/blob/main/proposals/csharp-7.2/readonly-ref.md#metadata-representation-of-in-parameters
    Private Shared Function ActuallyReceiveDummy(<System.Runtime.CompilerServices.IsReadOnlyAttribute()> ByRef dummy As Dummy) As Integer
        ' Do whatever you want here but don't modify dummy!
        Return dummy.GetHashCode() 
    End Function
    

    The VB.NET compiler does not seem to know about or account for this attribute in any way.

    Demo #4 here.

  • This whole idea does an end-run around the principle that the framework prevents in parameters from being modified, and so is super hacky. Thus you need to manually take care not to modify your ByRef dummy as Dummy argument in any way.

As an alternative, If you are willing to write a little bit of C# code, then as suggested in this answer by Sjoerd van Kreel to Recording Audio using XtAudio in VB.NET, you could write an adapter extension method in C# that creates a ReceiveDummy delegate from a delegate taking Dummy by value:

public delegate int ReceiveDummyByValue(Dummy dummy);

public static class DummyActions
{
    public static ReceiveDummy AsReceiveByReference(this ReceiveDummyByValue func) => (in Dummy d) => func(d);
}

Then in your main VB.NET code, use it e.g. as follows:

Private Shared Function ActuallyReceiveDummy(ByVal d As Dummy) As Integer
    ' Return whatever is required for dummy
    Return d.GetHashCode()
End Function

Public Shared Function CreateReceiveDummy() As ReceiveDummy
    Return (New ReceiveDummyByValue(AddressOf ActuallyReceiveDummy)).AsReceiveByReference()
End Function

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

How to implement a swift delegate method in objective-C having parameter?

How to implement AsRef for a struct containing references

C# Delegate from VB.NET

C# to VB.net delegate conversiom

Convert VB.NET delegate to C#

Struct containing Delegate of unknown type

How to add RaiseEvent for Delegate Error after conversion from C# to Vb.Net

How do I implement Debug for a struct containing a function type alias?

How to have a Delegate as a default parameter in C#

What's the VB.NET equivalent of async delegate in C#?

convert NamedPipeConnection delegate from C# to vb.net

How to implement protected access modifier for struct in C

How to implement apple watch crown delegate using objective c

julia implement convert for struct containing NTuple

Implement Iterator trait for a struct containing an iterable field

How to implement buttons in a delegate PyQt

How to pass an Optional parameter that is a struct in C#

VB.NET Private Function Implement C#

How can I mock a function delegate parameter in C#

How to provide default value for a parameter of delegate type in C#?

C# - How to pass List<T> to a delegate as parameter

How to add the last element into a vector of a struct containing an array in c++

How to read a file containing c-struct in nodeJS?

How to read a struct containing array of structs from TwinCat to C#

Copying a pointer-containing struct in C - how does it work?

C# pass parameter to delegate

vb.net delegate and invoke - Multithread

const Struct parameter in C

Delegate error converting from VB6 to vb.net