Pass an array from vba to c# using com-interop

2020-02-28 18:05发布

问题:

What is the proper way to pass an array of user defined classes from vba to .net (specifically c#) using com-interop?

Here's my c# code. If I call Method1 from vba it's failing with "Array or userdefined type expected" or "Function uses an automation type not supported in visual basic".

public class MyClass 
{
    public Method1(UserDefinedClass[] Parameters) { ... }
    public Method2(Object Parameters) { ... }
}

I've read a bit about the MarshallAsAttribute class. Could this be the missing piece in the c# code?

Here's the vba code I'm using:

Dim udt As New UserDefinedClass
Dim myArray()
myArray(1) = udt
myClass.Method1(myArray)
myClass.Method2(myArray)

回答1:

IIRC you have to pass arrays by reference.

Try declaring your method as

public class MyClass  
{ 
    public void Method1([In] ref UserDefinedClass[] Parameters) { ... } 
    ...
} 

If you don't want to pollute your class with ref parameters for .NET clients, you can define a ComVisible interface to be used by COM clients, and implement it explicitly thus:

[ComVisible(true)]
public interface IMyClass  
{ 
    void Method1([In] ref UserDefinedClass[] Parameters) { ... } 
    ...
} 

public class MyClass : IMyClass
{
    void IMyClass.Method1(ref UserDefinedClass[] Parameters)
    {
        this.Method1(Parameters);
    }

    public Method1(UserDefinedClass[] Parameters)
    {
        ...
    }
}

** In response to comment ** If you want to expose a collection instead of an array to VBA, you just need to expose an enumerator, and any other methods you want the VBA code to be able to call (e.g. Add, Remove, Insert, Clear, ...). E.g.

[ComVisible]
public interface IUserDefinedClassCollection
{
    IEnumerator GetEnumerator();

    int Count { get; };

    IUserDefinedClass this[int index] { get; }

    int Add(IUserDefinedClass item);

    // etc, other methods like Remove, Clear, ...
}

You can then use it as usual in VBA:

Dim objUserDefinedClasses As UserDefinedClassCollection
...
objUserDefinedClasses.Add objUserDefinedClass 
...
For nIndex = 0 To objUserDefinedClasses.Count

Next nIndex