如果结构有ReadOnlySpan字段,如何将ref结构参数传递给MethodInfo



我有一个代表方法的MethodInfo对象,该方法以ref struct为参数,该结构有一个ReadOnlySpan<byte>字段。如何通过MethodInfo对象调用该方法?我不能使用MethodInfo.Invoke,因为Invoke需要作为object?[]?数组的参数,而带有ReadOnlySpan<byte>字段的struct不能转换为object

那么,我如何通过反射调用一个方法,并向它传递一个ref结构值,其中该结构有一个类型为ReadOnlySpan的字段?

这可以通过MethodInfo.CreateDelegate()非常简单地实现。

下面是一个使用通用重载之一的示例,从.NET5.0:开始可用

public ref struct MyRefStruct
{
private ReadOnlySpan<byte> myReadOnlySpan;
public MyRefStruct(ReadOnlySpan<byte> myReadOnlySpan) =>
this.myReadOnlySpan = myReadOnlySpan;
public void Print()
{
foreach (byte b in myReadOnlySpan)
{
Console.WriteLine(b);
}
}
}
public class MyClass
{
private void PrintMyRefStruct(MyRefStruct myRefStruct) => myRefStruct.Print();
}
delegate void MyDelegate(MyRefStruct myRefStruct);
var myClass = new MyClass();
var myRefStruct = new MyRefStruct(new ReadOnlySpan<byte>(new byte[] { 0, 1 }));
var methodInfo = typeof(MyClass).GetMethod(
"PrintMyRefStruct",
BindingFlags.Instance | BindingFlags.NonPublic
);
methodInfo.CreateDelegate<MyDelegate>(myClass)(myRefStruct);

由于您的struct自然是一个ref struct,它将存在于堆栈上(并且无法逃到托管堆(,因此您面临编译器的几个限制,并且需要克服一些障碍。

  • ref结构不能是数组的元素类型
  • ref结构不能是类或非ref结构的字段的声明类型
  • ref结构无法实现接口
  • ref结构不能装箱为System.ValueType或System.Object
  • ref结构不能是类型参数。lambda表达式或局部函数无法捕获vA ref结构变量
  • ref结构变量不能在异步方法中使用。但是,您可以在同步方法中使用ref结构变量,例如返回Task或Task的
  • 在迭代器中不能使用ref结构变量

如您所见,ref struct不能在heap上装箱。这意味着您将无法强制转换为object并使用Invoke。但是,您可以使用表达式树relection.emit

当使用表达式树时,您需要将委托Expression.Lambda一起使用,因为ref struct不能用作Func中的类型参数

给定

public readonly ref struct Bob
{
public Bob(ReadOnlySpan<byte> myProperty)
=> MyProperty = myProperty;    
public ReadOnlySpan<byte> MyProperty { get; }
}
...
public static byte DoSomething(Bob bob)
=> bob.MyProperty[1]; // return something from the span ¯_(ツ)_/¯
delegate byte myDelegate(Bob asd);
...
var bytes = new byte[] {1, 2, 3};
var span = bytes.AsSpan();
var bob = new Bob(span);

用法

var method = typeof(SomeType).GetMethod("DoSomething");
var parameter = Expression.Parameter(typeof(Bob), "b");
var call = Expression.Call(method, parameter);
var expression = Expression.Lambda<myDelegate>(call, parameter);
var func = expression.Compile();
var result = func(bob);
Console.WriteLine(result);

结果

2

或者使用参数内修改器,您需要使用MakeByRefType

返回一个Type对象,该对象在作为参考参数

public static byte DoSomething(in Bob bob)
=> bob.MyProperty[1]; // return something from the span ¯_(ツ)_/¯
delegate byte myDelegate(in Bob asd);
...
var method = typeof(SomeType).GetMethod("DoSomething", new[] {typeof(Bob).MakeByRefType()});
var parameter = Expression.Parameter(typeof(Bob).MakeByRefType(), "b");
var call = Expression.Call(method, parameter);
var expression = Expression.Lambda<myDelegate>(call, parameter);
var func = expression.Compile();
var result = func(bob);

注意:这段代码不是完美表达的堡垒,但它应该可以工作。此外,这是为static方法构建的,如果它不是,则需要传入一个实例

相关内容

  • 没有找到相关文章

最新更新