C# 到 VB6 互操作:无法跨嵌套 COM 接口访问索引数组属性

C# to VB6 interop: indexed array properties are not accessible across nested COM interfaces

我想通过 COM 互操作发布一个 C# class 库,以便 VB6 客户端可以使用它。出于演示目的,请考虑以下代码段:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace cslib
{
    [ComVisible(true)]
    [Guid("...")]
    public interface IClass2
    {
        string m_sStr { get; set; }
    }

    [ComVisible(true)]
    [Guid("...")]
    [ClassInterface(ClassInterfaceType.None)]
    public class Class2 : IClass2
    {
        public Class2()
        {
            m_sStr = "Hello";
        }

        public string m_sStr { get; set; }
    }

    [ComVisible(true)]
    [Guid("...")]
    public interface IClass1
    {
        Class2[] m_Class2Instances { get; set; }
    }

    [ComVisible(true)]
    [Guid("...")]
    [ClassInterface(ClassInterfaceType.None)]
    public class Class1 : IClass1
    {
        public Class1()
        {
            List<Class2> lstClass2 = new List<Class2>();

            for (int i = 0; i < 5; i++)
                lstClass2.Add(new Class2());

            m_Class2Instances = lstClass2.ToArray();
        }

        public Class2[] m_Class2Instances { get; set; }
    }
}

在系统上注册库后,COM接口就可以在VB6中使用了。但是,使用索引值访问数组 属性 似乎不起作用:

Dim c1 As New cslib.Class1
Dim str As String

'Error message = Wrong number of arguments or invalid property assignment
str = c1.m_Class2Instances(0).m_sStr

我发现的唯一替代方法是创建一个临时数组变量。这允许我正确访问索引接口:

Dim c1 As New cslib.Class1
Dim str As String

'Works, but requires detour via temp array
Dim arrc2() As cslib.Class2
arrc2 = c1.m_Class2Instances

str = arrc2(0).m_sStr

不幸的是,我在这里说明的阵列仅仅是一种简化。在现实生活中,我需要访问位于嵌套数组结构深处的 COM 接口。例如,下面的 class 结构...

Class1
    Class2[]
        Class3[]
            Class4[]

...最终会迫使我创建三个临时数组变量,然后才能实际访问 Class4 的实例。

这是VB6的限制吗?如果是这样,有没有什么方法可以访问嵌套数组接口而不用临时变量弄乱代码?

我很久以前就停用了 VB6,不能再检查了。但几乎可以肯定它存在语法歧义。您是要索引 属性 还是 属性 的 return 值?您喜欢后一种解释,但事实并非如此。你必须这样写:

  str = (c1.m_Class2Instances)(0).m_sStr

或:

  str = c1.m_Class2Instances()(0).m_sStr

不知道这是否可以编译。无论如何。


您需要通过实际编写索引 属性 来取得成功。像这样:

public interface IClass1 {
    Class2 this[int index] { get; set; }
}

public class Class1 : IClass1 {
    private List<Class2> lstClass2 = new List<Class2>();
    public Class1() {
        for (int i = 0; i < 5; i++) lstClass2.Add(new Class2());
    }

    public Class2 this[int index] {
        get { return lstClass2[index]; }
        set { lstClass2[index] = value; }
    }
}

请注意,这还使 很多 不那么痛苦,让 VB6 代码迭代数组。您不会一遍又一遍地创建新数组。 VB6 代码也变得简短而有趣:

Dim c1 As New cslib.Class1
Dim str = c1(0).m_sStr

如果你真的,真的需要return或分配一个完整的数组,那么你必须使用一个方法来代替。