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...
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.
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