C# 4, to simplify COM interop, allow callers to COM interfaces to omit the ref keyword in front of arguments for by ref parameters.
I was surprised to see today that this also applies to extension methods that are extending COM interfaces. See the following, compiling, code:
using System;
using System.Runtime.InteropServices;
[ComImport, Guid ("cb4ac859-0589-483e-934d-b27845d5fe74")]
interface IFoo {
}
static class Program {
public static void Bar (this IFoo self, ref Guid id)
{
id = Guid.NewGuid ();
}
static void Main ()
{
Foo (null);
}
static void Foo (IFoo o)
{
Guid g = Guid.NewGuid ();
Console.WriteLine (g);
// note that g is passed as is, and not as ref g
o.Bar (g);
Console.WriteLine (g);
}
}
I didn't find anything in the spec to explain this behavior.
My feeling would be that code outside of the COM interface, even if it's an extension method extending a COM interface, should follow the regular C# rules, and enforce the usage of the ref keyword. I therefore filed a bug on connect. Not that I think this will be fixed, even if it's considered as a bug, there's already code out there relying on this.
Bug? Not a bug?
I don't think it's a bug; it looks more like "COM voodoo" as you say. Under the hood, the C# compiler emits something that is in fact correct, like this:
private static void Foo(IFoo o)
{
...
Guid g = Guid.NewGuid();
Guid <>r__ComRefCallLocal0 = g;
Bar(o, ref <>r__ComRefCallLocal0);
...
}
C# is in fact full of tricks. If you add a method to IFoo, like this for example,
[ComImport, Guid("cb4ac859-0589-483e-934d-b27845d5fe74")]
interface IFoo
{
void Test([Optional] ref object test);
}
you, again, will be able to declare this in C# 4:
static void Foo(IFoo o)
{
Guid g = Guid.NewGuid();
o.Test(g);
}
Of course, all this only works because CSC.EXE has an intimate knowledge of the ComImport attribute. These new magic Interop tricks were added to C# 4.0 to be able to easily interop with existing COM interfaces. Well, for Microsoft Office interfaces and methods mostly, and especially the armies of dreadful 'ref missing' parameters :-)
I don't think this is fully specified anywhere. This is all what the C# 4 specification has to say:
17.5 Attributes for Interoperation Note: This section is applicable only to the Microsoft .NET implementation of C#. 17.5.1 Interoperation with COM and Win32 components The .NET run-time provides a large number of attributes that enable C# programs to interoperate with components written using COM and Win32 DLLs. For example, the DllImport attribute can be used on a static extern method to indicate that the implementation of the method is to be found in a Win32 DLL. These attributes are found in the System.Runtime.InteropServices namespace, and detailed documentation for these attributes is found in the .NET runtime documentation.
And here are some pages on MSDN:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With