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

3
我想通过COM互操作发布一个C#类库,以便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接口。例如,以下类结构...

Class1
    Class2[]
        Class3[]
            Class4[]

...最终强制我创建三个临时数组变量,才能真正访问Class4的实例。

这是VB6的限制吗?如果是,有没有办法在不用大量临时变量的情况下访问嵌套数组接口?

1个回答

3

我很久之前就已经退出了VB6,无法再进行检查。但几乎可以确定它存在语法歧义。你是想对属性进行索引还是对属性的返回值进行索引?你倾向于后者的解释,但那不是它的实际作用。你需要写类似这样的代码:

  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

如果您确实需要返回或分配完整的数组,则必须使用方法。

注:在此处“方法”指的是函数。

不幸的是,只有在类中包含单个实例数组时才能起作用。一旦存在两个或更多的数组,索引的 this 属性将导致一个模糊的符号。 - Aurora
1
设计您的对象模型以与可用工具相互配合。请注意,您可以在VB.NET代码中声明接口,它允许任意索引属性。 - Hans Passant
你的第二个VB6代码片段似乎朝着正确的方向发展。然而,我在使用第二个嵌套数组之后的语法时遇到了麻烦。str = c1.m_Class2Instances()(0).m_sStr是可以工作的,而str = c1.m_Class2Instances()(0).m_Class3Instances()(0).m_sStr会导致语法错误。 - Aurora
难以相信你真的在使用它。祝你好运,你需要靠自己去解决它。 - Hans Passant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接