Reputation: 146
I have a first c# assembly exposing a class and an enum
namespace TestComLibraryInCSharp
{
[Guid("A5AE3B4C-7788-4394-A949-98A9F78A8E00")]
[ComVisible(true)]
public enum ColorType
{
Red = 0,
Green = 1,
Blue = 2
}
[Guid("EF5D9F9C-DAAB-472E-A418-114F0352F06E")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[ComVisible(true)]
public interface IComClassUsingEnum
{
void Select(ColorType color);
}
[Guid("5EDE0D14-3A3B-41E7-93BC-40868BC68655")]
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
public class ComClassUsingEnum : IComClassUsingEnum
{
public void Select(ColorType color)
{
MessageBox.Show("you have selected " + color.ToString());
}
}
}
In another assembly I want to test the above interface using dynamic
public void DoTestColor()
{
Type type = Type.GetTypeFromProgID("TestComLibraryInCSharp.ComClassUsingEnum");
dynamic c = Activator.CreateInstance(type);
c.Select(0); // this works
c.Select(1); // this throws RuntimeBinderException
}
c.Select(0) works showing the messagebox
c.Select(1) (or any other number except 0) will generate this exception
An unhandled exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in System.Core.dll
Additional information: The best overloaded method match for 'TestComLibraryInCSharp.ComClassUsingEnum.Select(TestComLibraryInCSharp.ColorType)' has some invalid arguments
in vba, late bound, everything works as expected
Dim c As Object
Set c = CreateObject("TestComLibraryInCSharp.ComClassUsingEnum")
c.Select 1
What is the correct way to pass enum values with late bound in c#?
Upvotes: 1
Views: 220
Reputation: 146
As much as Hans is right, a solution could be this
public ColorType GetColorTypeFromInt(int colorTypeAsInt)
{
return (ColorType) colorTypeAsInt;
}
that is, in the COM library, expose some helper method which casts from an int to the proper enum type (which maybe is what Hans referred to as 'sneaky backdoor').
Quite ugly, but answers my original question.
Upvotes: 0
Reputation: 942010
It is a very good example that demonstrates that writing COM server testing code in .NET does not actually test COM interop at all. And why the IDE objecting against adding a reference to the type library is a very legitimate complaint. The CLR is not that easily fooled, it can see at runtime that you create a .NET object, it will not create an RCW for it. Not to make your life difficult, just because it is more efficient.
The exception is otherwise entirely normal. The DLR follows C# language rules, only the default value (0) can be implicitly converted to an enum type. It insists on seeing a ColorType otherwise, you'd use a cast in a C# program. That's awfully hard to come by in a late-bound scenario, you can't give the enum type a ProgId. Some kind of sneaky backdoor reflection code would be needed, well beyond what's reasonable in a sane test.
Given that you don't actually test COM interop at all, you might as well punt the problem and add a normal .NET reference. Now it is simple. Only the VBA test code exercises the COM interop plumbing.
Upvotes: 1