C# 从VBA访问.NET通用对象

C# 从VBA访问.NET通用对象,c#,.net,vba,com,interop,C#,.net,Vba,Com,Interop,我的.net代码有一个具有许多通用属性的对象。此对象将返回到VBA代码。所有非泛型属性都运行良好,但我还需要访问泛型值。有没有一种方法可以从VBA中执行此操作 [ClassInterface(ClassInterfaceType.AutoDual)] public class Obj { public string GetProp1() {...} public IList<MyCustomType> GetProp2() {...} } 您不能直接执行此操作(如果

我的.net代码有一个具有许多通用属性的对象。此对象将返回到VBA代码。所有非泛型属性都运行良好,但我还需要访问泛型值。有没有一种方法可以从VBA中执行此操作

[ClassInterface(ClassInterfaceType.AutoDual)]
public class Obj
{
    public string GetProp1() {...}
    public IList<MyCustomType> GetProp2() {...}
}

您不能直接执行此操作(如果VS正在进行COM注册,您应该会看到类似这样的警告:类型库导出器警告正在处理“NS.Obj.get_GetProp2(#1),Assy”。警告:类型库导出器在签名中遇到泛型类型实例。泛型代码可能无法导出到COM

您需要做的是制作一个小的非通用包装器和一个向COM公开的接口(假设您需要强类型对象)。只要您引用VBA中的类型库并通过强类型VBA引用访问对象,您就可以执行以下操作:

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class Class1
{
    public IMyListOfString Strings {get; set;}
    public Class1()
    {
        Strings = new MyListOfString() { "Foo", "Bar", "Baz" };
    }
}

[ComDefaultInterface(typeof(IMyListOfString))]
public class MyListOfString : List<string>, IMyListOfString { }

[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IMyListOfString
{
    [DispId(0)]
    string this[int idx] { get; set; }
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
公共班级1
{
公共IMyListOfString字符串{get;set;}
公共类别1()
{
Strings=newmylistofstring(){“Foo”、“Bar”、“Baz”};
}
}
[ComDefaultInterface(typeof(IMyListOfString))]
公共类MyListOfString:List,IMyListOfString{}
[ComVisible(true)]
[接口类型(ComInterfaceType.InterfaceIsDual)]
公共接口IMyListOfString
{
[DispId(0)]
字符串[int idx]{get;set;}
}
有一个技巧可以让它在不引用VBA中的托管类型库的情况下工作(例如,latebound)也一样,但我已经离开COM互操作世界太久了,记不起它是什么了。

我发现描述了一个难看的黑客——通过反射调用所有东西。由于通用值仍然作为对象返回,反射应该可以工作,但1)速度慢,2)容易出错,3)调用起来非常不方便

如本文所示,我将使用具有以下签名的实用程序方法:

public object GetProperty(object Instance, string Property)
public object InvokeMethod(object Instance, string Method)
public object InvokeMethod_OneParm(object Instance, string Method, object Parm1)
public object InvokeMethod_TwoParms(object Instance, string Method, object Parm1, object Parm2)
public void SetProperty(object Instance, string Property, object Value)

丑陋,但可行。

警告建议如@Matt Davis的回答中所述解决此问题
public object GetProperty(object Instance, string Property)
public object InvokeMethod(object Instance, string Method)
public object InvokeMethod_OneParm(object Instance, string Method, object Parm1)
public object InvokeMethod_TwoParms(object Instance, string Method, object Parm1, object Parm2)
public void SetProperty(object Instance, string Property, object Value)