Since your struct
would naturally be a ref struct
which will live on the stack (and can't escape to the managed heap), you face several compiler limitations and have a few hurdles to overcome.
- A ref struct can't be the element type of an array.
- A ref struct can't be a declared type of a field of a class or a non-ref struct.
- A ref struct can't implement interfaces.
- A ref struct can't be boxed to System.ValueType or System.Object.
- A ref struct can't be a type argument. vA ref struct variable can't be captured by a lambda expression or a local function.
- A ref struct variable can't be used in an async method. However, you can use ref struct variables in synchronous methods, for example, in
those that return Task or Task.
- A ref struct variable can't be used in iterators.
As you can see, ref struct
can't be boxed on the heap
. This means you will not be able to cast to an object
and use Invoke
. However you can use an expression tree or relection.emit
When using an expression tree you will need to use a delegate with Expression.Lambda
as ref struct
can't be used as type parameters in a Func
.
Given
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);
Usage
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);
Results
2
Or with the in parameter modifier you'll need to make use of MakeByRefType
Returns a Type object that represents the current type when passed as
a ref parameter
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);
Note : This code is not the bastion perfect expression'ing, however it should work. Also this is built for a static
method, you will need to pass in an instance if it's not