-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
I propose this method in the System.Runtime.CompilerServices.RuntimeHelpers class:
public static void ForwardArguments(RuntimeMethodHandle method, ArgIterator args, __arglist);This would call the specified method (which must be variadic), passing along the remaining arguments from the ArgIterator to the variadic parameter, and the variadic arguments from the method as normal parameters. If the number of variadic arguments passed to ForwardArguments is larger than the number of arguments the method takes (throw an exception if smaller), they could be prepended before the variadic arguments passed from args.
Example usage:
public static void VarArgs(int arg, __arglist)
{
Console.WriteLine(arg);
var ai = new ArgIterator(__arglist);
while(ai.GetRemainingCount() > 0)
{
Console.WriteLine(TypedReference.ToObject(ai.GetNextArg()));
}
}
public static void Forward(__arglist)
{
var ai = new ArgIterator(__arglist);
int num = __refvalue(ai.GetNextArg(), int);
ForwardArguments(ldtoken(VarArgs), ai, __arglist(num, "hello"));
}
Forward(__arglist(42, "world")); //outputs "42", "hello", "world"This extracts the integer from the argument list, and passes it with the rest to VarArgs. ldtoken serves as a replacement of the ldtoken CIL instruction (for fast reflection).
I have observed the need of this method while reporting dotnet/roslyn#24348, when a bridge virtual method must be generated to implement an interface method with a non-virtual method from a base class in another assembly. In the case of a variadic method, there is no support in CIL to forward variadic arguments to another method without having to deal with complex reflection, and thus a code that would normally compile in C# for a single assembly fails if the base class is present in a different assembly.
The bridge method could be generated if the proposed method was available:
class MyVarArgs : VarArgs, IVarArgs
{
void IVarArgs.Invoke(__arglist)
{
RuntimeHelpers.ForwardArguments(ldtoken(base.Invoke), new ArgIterator(__arglist), __arglist(this));
}
}The usefulness of this method is apparent in this case, but it can also be used for variadic reflection, which is not supported much at the moment, and other languages that use variadic methods can profit from this as well, using it either implicitly like C#, or explicitly.
There should also be variations of this method returning object and generic T and ref T, to accomodate for all return types. Another overload taking RuntimeArgumentHandle instead of ArgIterator could be also possible for additional performance (not having to construct the iterator for simple forwarding methods).
If the called method isn't variadic, the ArgIterator must be empty, but the other arguments could still be passed via normal parameters of the method, allowing invoking a method without having to construct an object array, or a delegate (and allowing passing references).
My reason for including the method in RuntimeHelpers and not MethodInfo is mainly for speed, since it would have to be instantiated every time, and it would be used mainly to implement language features.