How does a COM server marshal nullable in C# class

2019-06-17 15:28发布

问题:

I hear that Nullable<T> is a C# generic class and it does not work with COM - like any other generic class.

Well, in my C# class library I have:

[InterfaceType(ComInterfaceType.InterfaceIsDual),
Guid("2FCEF713-CD2E-4ACB-A9CE-E57E7F51E72E")]
public interface ICOMClass
{
    int? GetNullable();
}

[ClassInterface(ClassInterfaceType.None)]
[Guid("57BBEC44-C6E6-4E14-989A-B6DB7CF6FBEB")]
public class COMClass : ICOMClass
{
    public int? GetNullable()
    {
        int? hello = null;
        return hello;
    }
}

Surprisingly that compiles and I am able to attach references to my COMClass library in VBE.

I know that:

  • VBA does not list .GetNullable() in the list of members on Object Browser (even with show hidden members ticked)
  • VBA does not list .GetNullable() in the intelli-sense drop down

but why:

Dim c as new COMClass
c.GetNullable

does not throw a rather expected Object doesn't support this property or method?

as opposed to:

c.NonExistingMethod

Can anyone explain why?

I am suspicious that it has something to do with ComInterfaceType Enumeration because

  • both: InterfaceIsDual & InterfaceIsIDispatch act just like I described above

but:

  • InterfaceIsIUnknown actually doesn't seem to marshal/touch the GetNullable() and the expected error is thrown...

Can anyone explain this behaviour?

回答1:

Well, it compiles. But you know you got trouble when you try to create a type library for the DLL:

C:\projects2\ClassLibrary38\bin\Debug>tlbexp ClassLibrary38.dll
Microsoft (R) .NET Framework Assembly to Type Library Converter 4.0.30319.33440
Copyright (C) Microsoft Corporation.  All rights reserved.

TlbExp : warning TX8013117D : Type library exporter warning processing 'ICOMClas
s.GetNullable(#0), ClassLibrary38'. Warning: Type library exporter encountered a
 generic type instance in a signature. Generic code may not be exported to COM.
Assembly exported to 'C:\projects2\ClassLibrary38\bin\Debug\ClassLibrary38.tlb'

You can look at it by running OleView.exe on the type library. This is what your interface looks like:

[
  odl,
  uuid(2FCEF713-CD2E-4ACB-A9CE-E57E7F51E72E),
  version(1.0),
  dual,
  oleautomation,
  custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "ICOMClass")

]
interface ICOMClass : IDispatch {
};

Nothing, nada, zippo. Microsoft programmers sometimes are too friendly when they write diagnostic message. It is not just "may not be", it is "will not be".

This is not going to work. That it can find the method by late binding won't help, the return value cannot be interpreted properly, Nullable<T> is not [ComVisible]. As an alternative, consider that COM always had to notion of "nullability", strongly supported in VBA which depends on it a great deal. Variants can store vtNull or vtEmpty to indicate that a value is not set. It is object in C# code.