This is a partially working proof of concept for #663, but it still needs quite a bit of work:
[ ] verify that converter types implement the implicit protocol correctly before emitting code that invokes them
[X] perform value conversion for inbound by-ref-like values (in by-value and in method parameters)
[ ] perform value conversion for outbound by-ref-like values (in method return values, ref and out parameters)
[ ] add unit tests
[ ] add documentation on how to use ProxyGenerationOptions.ByRefLikeConverterSelector
[X] ideally, support generic converter types
Usage example 1: defining conversions for by-ref-like argument values
This shows how one would set up a converter for by-ref-like argument values. In this case, one gets set up such that Span<byte> arguments will get converted to a byte[] copy during invocation:
// this will get invoked during interception:
public class CopyByteSpanConverter
{
// a converter for by-ref-like argument values must be accessible to the dynamically generated assembly,
// and it must have...
// (1) for inbound conversions, a public `Box` method
// with a single `in` parameter of a by-ref-like type, and return type `object`:
public object Box(in Span<byte> span)
{
return span.ToArray();
}
// (2) for outbound conversions, a public `Unbox` method
// with an `object` parameter and a `ref` parameter of a by-ref-like type:
public void Unbox(object argument, ref Span<byte> span)
{
var array = (byte[])argument;
array.CopyTo(span);
}
}
// this will get invoked during proxy type generation:
class ConverterSelector : IByRefLikeConverterSelector
{
public Type SelectConverterType(MethodInfo method, int parameterPosition, Type parameterType)
{
return parameterType == typeof(Span<byte>) ? typeof(CopyByteSpanConverter) : null;
}
}
// this is what we want to proxy:
public interface IFoo
{
void Method(in Span<byte> bytes);
}
var generator = new ProxyGenerator();
var options = new ProxyGenerationOptions { ByRefLikeConverterSelector = new ConverterSelector() };
var proxy = generator.CreateInterfaceProxyWithoutTarget<IFoo>(options, ...);
var span = new byte[] { ... }.AsSpan();
proxy.Method(in span); // this argument will end up in the invocation's `Arguments` as a `byte[]` array!
Usage example 2: new default / fallback behavior
If no converter is set up, by-ref-like argument values no longer cause an exception during invocation, but now get converted to null references in the IInvocation.Arguments array.
// this is what we want to proxy:
public interface IFoo
{
void Method(in Span<byte> bytes);
}
var generator = new ProxyGenerator();
var span = new byte[] { ... }.AsSpan();
proxy.Method(in span); // this argument will end up in the interceptor's `Arguments` as a `null` reference
This is a partially working proof of concept for #663, but it still needs quite a bit of work:
in
method parameters)ref
andout
parameters)ProxyGenerationOptions.ByRefLikeConverterSelector
ideally, support generic converter typesUsage example 1: defining conversions for by-ref-like argument values
This shows how one would set up a converter for by-ref-like argument values. In this case, one gets set up such that
Span<byte>
arguments will get converted to abyte[]
copy during invocation:Usage example 2: new default / fallback behavior
If no converter is set up, by-ref-like argument values no longer cause an exception during invocation, but now get converted to
null
references in theIInvocation.Arguments
array.