这是extremely hacky,但事实证明(在.NET 7中)使用Delegate.CreateDelegate()
从其签名实际接受ref
参数的静态方法创建带有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));
}
}
我可以做到:
var receiveMethod = DummyActions.CreateReceiveDummy();
Console.WriteLine(receiveMethod(new Dummy()));
A它起作用了!演示#1here.
翻译成VB.NET,我得到以下结果:
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
这使得在VB.NET中实现以下功能成为可能:
Dim receiveMethod = DummyActions.CreateReceiveDummy()
Console.WriteLine(receiveMethod(New Dummy()))
样机小提琴#2 here
备注:
根据design documents for in
in C# 7.2名
如果将System.Runtime.CompilerServices.IsReadOnlyAttribute
应用于byref参数,则意味着该参数是in
参数.
此外,如果方法是抽象的或虚拟的,则此类参数(且仅此类参数)的签名必须为modreq[System.Runtime.InteropServices.InAttribute]
.
动机:这样做是为了确保在方法覆盖/实现In参数的情况下匹配.
同样的要求也适用于委托中的Invoke
个方法.
动机:这是为了确保现有的编译器在创建或分配委托时不能简单地忽略readonly
.
原来in C#编译器不允许你手动应用IsReadOnlyAttribute
,如果你try 了,你会得到一个编译器错误Do not use 'System.Runtime.CompilerServices.IsReadOnlyAttribute'. This is reserved for compiler usage.(演示#3 here).但VB.NET编译器没有这样的限制,因此,如果您想要针对判断此属性的某个可能的Delegate.CreateDelegate()
future 版本"保护"您的方法,您可以手动添加它:
' 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
VB.NET编译器似乎不知道或以任何方式说明此属性.
演示#4 here.
整个 idea 都是围绕着框架防止in
个参数被修改这一原则进行的,因此是超级老套的.因此,您需要手动注意不要以任何方式修改您的ByRef dummy as Dummy
参数.
As an alternative,如果您愿意编写一点C#代码,那么按照this answerxSjoerd van Kreel到102中的建议,您可以用C#编写一个adapter扩展方法,该方法从通过值获取Dummy
的委托创建ReceiveDummy
委托:
public delegate int ReceiveDummyByValue(Dummy dummy);
public static class DummyActions
{
public static ReceiveDummy AsReceiveByReference(this ReceiveDummyByValue func) => (in Dummy d) => func(d);
}
然后在您的主要VB.NET代码中使用它,例如,如下所示:
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