可以使用com interop将变量数组传递给C#吗?

时间:2011-05-10 15:36:46

标签: c# vba com-interop

我尝试在Excel和C#之间传输一些数据。为此,我编写了一个简单的C#类,其中包含一个用于设置和获取数据的属性。

[Guid("xxx")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public class Vector
{
    private object[,] _values;

    public object[,] ExcelValues
    {
        get { ... }
        set { ... }
    }
}

在VBA中获取ExcelValues属性效果很好,但无法在VBA中设置它。如果我尝试设置属性,则VBA代码无法编译:

    Dim values As Variant
    With myRange
        ' typo: Set values = Range(.Offset(0, 0), .Offset(100, 0))
        values = Range(.Offset(0, 0), .Offset(100, 0))
    End With

    Dim data As New Vector

    ' this doesn't compile
    data.ExcelValues = values      

    ' this works
    values = data.ExcelValues

有关我如何能够完成此任务的建议,而无需一次设置变量数组中的每个值吗?

2 个答案:

答案 0 :(得分:3)

我找到了一个基于已发布here的代码的解决方案。变量数组必须作为对象从VBA传递到C#(而不是对象[,])。然后可以使用反射将其转换为更方便的东西:

[Guid("xxx")]
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class Vector
{        
    [ComVisible(false)]
    public IList<double> Values { get; set; }

    public object[,] GetExcelValues()
    {
        // own extension method
        return Values.ConvertToExcelColumn();
    }

    public void SetExcelValues(object comArray)
    {
        IEnumerable<object> values = ConvertExcelCloumnToEnumerable(comArray);
        Values = new List<double>(values.Select(Convert.ToDouble));
    }

    private static IEnumerable<object> ConvertExcelCloumnToEnumerable(object comObject)
    {
        Type comObjectType = comObject.GetType();

        if (comObjectType != typeof(object[,]))
            return new object[0];

        int count = (int)comObjectType.InvokeMember("Length", BindingFlags.GetProperty, null, comObject, null);
        var result = new List<object>(count);

        var indexArgs = new object[2];
        for (int i = 1; i <= count; i++)
        {
            indexArgs[0] = i;
            indexArgs[1] = 1;
            object valueAtIndex = comObjectType.InvokeMember("GetValue", BindingFlags.InvokeMethod, null, comObject, indexArgs);
            result.Add(valueAtIndex);
        }

        return result;
    }
}

另一种方式 - 从C#到VBA - 它可以作为对象[,]或双[,]传递得更舒服。
希望没有语法拼写错误:)。

答案 1 :(得分:0)

通过使用Set,你告诉VBA“values”是一个对象(在本例中是一个Range),但是当你将它赋给ExcelValues时你没有使用set。在阅读值时尝试删除Set。

With myRange         
    values = Range(.Offset(0, 0), .Offset(100, 0)).Value     
End With