是否可以使用 com 互操作将变体数组传递给 C#
本文关键字:数组 可以使 com 互操作 是否 | 更新日期: 2023-09-27 17:56:04
我尝试在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
任何建议我如何在不一次设置变体数组中的每个值的情况下完成此操作?
我找到了一个基于此处发布的代码的解决方案。变体数组必须作为对象(而不是对象 [,])从 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 - 它可以作为对象 [,] 或双精度 [,] 传递得更舒适。
希望没有语法错别字:)。
通过使用 Set,您告诉 VBA "值"是一个对象(在本例中为 Range),但在将其分配给 ExcelValues 时不使用 set。 尝试在读取值时删除 Set。
With myRange
values = Range(.Offset(0, 0), .Offset(100, 0)).Value
End With