Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Possible nasty side effects of tricking .Net to have optional ref parameters for COM

Tags:

c#

.net

excel

vba

com

FINAL EDIT

I've more thoroughly tested the "feature" and written a complete article about it: Optional passed by reference parameters with C# for VBA COM APIs

Any feedback is welcome.


For whatever reason in C# a method can't have optional passed by reference (marked with ref or out) parameters.

But in other infrastructures like VBA, VB6 or COM this is possible.

When bridging C# with VBA using COM I've found a way to overcome the C# limitation by marking the ref parameters as [Optional] which is AFAIK what the C# compiler generates at the end of its plumbing.

void SomeDotNetCSMethod([Optional] ref someParameter)

This seems to work like a charm: when calling from VBA to C# I can omit the ref parameters and of course I can read and change them from the .Net/C# side.

But as I've not found any writing about it I'd like to be sure there is no bad side effects with this "trick".

Do you know any ? Can you imagine any ?


EDIT

With [DefaultParameterValue] attribute I may have found a way to have VBA see the default values for the parameter, but only for some types.

I'll do more tests to confirm this is working as expected...

like image 827
Pragmateek Avatar asked Aug 23 '15 17:08

Pragmateek


1 Answers

No, this is not a generic way to specify an optional argument. You are taking advantage of a pretty quirky feature that was added in C# v4, it made Office interop programming more palatable. You can normally expect it to have the intended effect the closer the interop layer resembles VBA or IDispatch (aka COM Automation). It is not a general COM mechanism, the more universal way is for the client compiler to observe the [defaultvalue] attribute in the type library and to apply the value in the method call. Much like C# does it.

The type of the argument matters a great deal, you forgot to specify it in your snippet. But with the expectation that it is object. Which matches VARIANT in the COM server, a pretty common type in Visual Basic. Also explains ref, the default argument passing in old VB versions was ByRef.

Before C# v4 it was a very tedious affair to write C# code to call such a server, particularly Office interop code was peppered with a very large amount of ref Type.Missing. Otherwise inspired by the need for supporting scripting languages, the kind of environment where it is impossible to determine the default value of an optional argument from the type library. So a convention was needed to pass the "caller did not specify the argument" signal to the callee, they chose a variant of type vtError with the value set to DISP_E_PARAMNOTFOUND. Compatible with IDispatch::Invoke().

Note how this is very, very different from the way optional parameters are dealt with in C# and any other language. It is always the caller that resolves the default value for an optional argument, the callee is entirely unaware that the code omitted the argument. In the case of C#, that default value is encoded as a .param value in the metadata. The compiler uses the default where necessary to compile the method call.

If the argument type is not object then you'll invoke a different quirk, now the caller sets the default. It will be null for an object or interface. And of course it depends on how the code you call interprets the variant value as 'optional'. Note that vtNull or vtEmpty can have the same semantic meaning.

like image 125
Hans Passant Avatar answered Sep 23 '22 14:09

Hans Passant