代码之家  ›  专栏  ›  技术社区  ›  Aurora

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

  •  3
  • Aurora  · 技术社区  · 9 年前

    我想通过COM interop发布一个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 回复  |  直到 9 年前
        1
  •  3
  •   Hans Passant    9 年前

    我很早以前就退休了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
    

    如果你真的, 真正地 需要返回或分配一个完整的数组,则必须改用方法。