-
Notifications
You must be signed in to change notification settings - Fork 471
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support by-ref-like (ref struct
) parameter types such as Span<T>
and ReadOnlySpan<T>
#663
Comments
This comment was marked as outdated.
This comment was marked as outdated.
Scratch the above proposal, I think I can actually come up with one that works for arbitrary by-ref-like types. I'll post an updated feature proposal shortly. |
I've put something together that appears to work... see the draft PR linked above (#664) for two short code examples how this would be used in practice. I'd be glad for some feedback (and whether the suggested API would actually be usable e. g. in downstream testing libraries). /cc @thomaslevesque & @blairconrad (FakeItEasy), @dtchepak & @zvirja (NSubstitute), @jonorossi |
Hey @stakx, nice job! |
Thanks for the feedback @thomaslevesque.
Yes, there is. |
True. I don't see what we could do about that, though... do you? If I understand your concern correctly, this would make it only impossible to do round-tripping of |
Indeed. Which is why the copying behavior shouldn't be the default behavior (for spans), and why I thought it would be a good idea for the converter selectors to pinpoint single method parameters, so you're free to choose to nullify most spans except where retaining the value somehow – e.g. as an array copy – is actually important. Being only able to set up a single converter globally that gets used for all by-ref-like parameters equally might be too coarse-grained. I've also briefly considered doing weird |
Thanks, @stakx. Slightly over my head, but in general, I think I understand the approach and the tradeoffs. Appreciate your work. Thanks for thinking of us to invite for comments. The possible performance optimization by specifying the position of the parameter is interesting, and not something I would've thought of. Just to make sure I understand everything, if I combine that power with a comment @thomaslevesque made earlier ("From FakeItEasy's perspective, I think the converters for // 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;
}
} where we'd end up ignoring the |
@blairconrad, I suppose that you'd typically configure a converter out-of-the-box that checks for both For mocking libraries, the selector's method body could look like this: if (parameterType.IsGenericType)
{
var def = parameterType.GetGenericTypeDefinition();
var args = paramrterType.GetGenericArguments();
if (def == typeof(Span<>))
{
return typeof(CopySpanConverter<>).MakeGenericType(args);
}
else if (def == typeof(ReadOnlySpan<>)
{
// as above but with a CopyReadOnlySpanConverter<> instead
}
}
// for all other by-ref-like types, either
// * delegate to user-provided selector function; or
// * return null to let DynamicProxy nullify everything. (Btw., I'm not 100% sure yet whether the |
Ah, yes, of course. Thanks for the reply!
No... I'm not even sure there is a solution. I'm just pointing out a limitation.
Yeah, half-trips would probably work in most cases. |
DynamicProxy does not currently support those because by-ref-like values cannot be boxed to be put in the
object[] IInvocation.Arguments
array.I haven't yet been able to think of a general way how all by-ref-like types (including user-defined ones) could be supported, ecause of their various limitations. If anyone has ideas, I'd be interested in hearing them!However, it might be fairly easy to at least add support forSpan<T>
andReadOnlySpan<T>
specifically. Those types are becoming more and more common in the .NET FCL, so while not an ideal solution, it might still be sufficient for most use cases:We could introduce a new type in DynamicProxy's namespace:Then we could introduce a new property toProxyGenerationOptions
,ISpanMarshaller SpanMarshaller { get; set; }
, which would get injected into generated proxies so they could use it to transfer spans into and out of theobject[] IInvocation.Arguments
array.I don't really like an addition that deals with two very specific types, but they are becoming more and more common, and I haven't yet been able to come up with a more general mechanism.Update
See the PR linked further down for an updated proposal that supports arbitrary by-ref-like types, including user-defined ones.
Opinions, or alternate ideas, anyone?
The text was updated successfully, but these errors were encountered: