You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取数组的COM对象类型?解决VBA自定义对象数组去重类型异常

目标

通过反射与泛型传入自定义对象的VBA数组,处理后返回相同类型的VBA COM对象(示例功能为对以变体形式传入的任意类型VBA数组去重)。

现状

值类型数组处理符合预期,返回与传入类型一致的数组(参考RemoveDuplicates方法)。

问题

自定义VBA对象数组(如Person数组)处理后,返回的是包含Person对象的变体数组,而非预期的Person数组。

临时方案

使用RemoveDuplicates2方法传入VBA数组和非泛型IEqualityComparer可实现自定义对象数组去重,但无法返回所需的自定义COM对象数组。

备注

目前为避免潜在问题,将Array.cs中的RemoveDuplicates重载命名为唯一名称,后续需研究表达式树相关内容。


SafeArraySingleton.cs

using GSystem = global::System;
using GArray = global::System.Array;
using GType = global::System.Type;
using GMethodInfo = global::System.Reflection.MethodInfo;

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Collections;
using DotNetLib.System.Collections.Generic;

namespace DotNetLib.System
{
    [ComVisible(true)]
    [Description("Provides methods for creating, manipulating, searching, and sorting safe arrays.")]
    [Guid("37592E87-83CE-4D47-A510-324FE529BE27")]
    [ProgId("DotNetLib.System.SafeArraySingleton")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComDefaultInterface(typeof(ISafeArraySingleton))]
    public class SafeArraySingleton : ISafeArraySingleton
    {
        const string RemoveDuplicatesMethod = "RemoveDuplicates";
        static GType _arrayType = typeof(Array);
        static  GMethodInfo _removeDuplicates = _arrayType.GetMethod("RemoveDuplicates",
                                                BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);


        static GMethodInfo _removeDuplicates2 = _arrayType.GetMethod("RemoveDuplicates2",
                                                BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
        static GType _genericComparerType = typeof(GenericEqualityComparer<>);

        public SafeArraySingleton() { }

        [return: MarshalAs(UnmanagedType.Struct, SafeArraySubType = VarEnum.VT_ARRAY)]
        public object RemoveDuplicates([MarshalAs(UnmanagedType.Struct, SafeArraySubType = VarEnum.VT_ARRAY)][In] ref object inputArray)
        {
            if ((inputArray == null) | !(inputArray is GArray))
            {
                throw new ArgumentException("Must be an array.", nameof(inputArray));
            }
            var result = _removeDuplicates.MakeGenericMethod(inputArray.GetType().GetElementType()).Invoke(null, new object[] { inputArray });
            return result;
        }

        [return: MarshalAs(UnmanagedType.Struct, SafeArraySubType = VarEnum.VT_ARRAY)]
        public object RemoveDuplicates2([MarshalAs(UnmanagedType.Struct, SafeArraySubType = VarEnum.VT_ARRAY)][In] ref object inputArray, IEqualityComparer nonGenericComparer)
        {
            if ((inputArray == null) | !(inputArray is GSystem.Array))
            {
                throw new ArgumentException("Must be an array.", nameof(inputArray));
            }

            GType elementType = inputArray.GetType().GetElementType();

            // 创建非泛型比较器的泛型包装器(通过反射)
            var genericComparerType = typeof(GenericEqualityComparer<>);
            var genericType = genericComparerType.MakeGenericType(elementType);
            var genericComparer = Activator.CreateInstance(genericType, nonGenericComparer);

            var result = _removeDuplicates2.MakeGenericMethod(elementType).Invoke(null, new object[] { inputArray, genericComparer });
            return result;
        }

    }
}

ISafeArraySingleton.cs

using GCollections = global::System.Collections;
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace DotNetLib.System
{
    [ComVisible(true)]
    [Guid("5B473306-F5E2-4C83-92F7-CEF4A363E2DD")]
    [Description("Provides methods for creating, manipulating, searching, and sorting safe arrays.")]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface ISafeArraySingleton
    {
        [Description("Removes duplicates from an array.")]
        [return: MarshalAs(UnmanagedType.Struct, SafeArraySubType = VarEnum.VT_ARRAY)]
        object RemoveDuplicates([MarshalAs(UnmanagedType.Struct, SafeArraySubType = VarEnum.VT_ARRAY)][In] ref object inputArray);

        [Description("Removes duplicates from an array.")]
        [return: MarshalAs(UnmanagedType.Struct, SafeArraySubType = VarEnum.VT_ARRAY)]
        object RemoveDuplicates2([MarshalAs(UnmanagedType.Struct, SafeArraySubType = VarEnum.VT_ARRAY)][In] ref object inputArray, GCollections.IEqualityComparer equalityComparer);

    }
}

Array.cs 相关代码

public static T[] RemoveDuplicates<T>(T[] inputArray)
        {
            if (inputArray == null)
                throw new ArgumentNullException(nameof(inputArray));

            HashSet<T> set = new HashSet<T>(inputArray);
            return set.ToArray();
        }

        public static T[] RemoveDuplicates2<T>(T[] inputArray, IEqualityComparer<T> equalityComparer)
        {
            if (inputArray == null)
                throw new ArgumentNullException(nameof(inputArray));

            HashSet<T> set = new HashSet<T>(inputArray, equalityComparer);
            return set.ToArray();
        }

GenericEqualityComparer.cs

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

namespace DotNetLib.System.Collections.Generic
{
    [ComVisible(false)]
    // 非泛型IEqualityComparer的泛型包装器
    // GenericEqualityComparer<T>是一个泛型包装器,将调用委托给非泛型比较器
    public class GenericEqualityComparer<T> : IEqualityComparer<T>
    {
        private readonly IEqualityComparer originalComparer;

        public GenericEqualityComparer(IEqualityComparer originalComparer)
        {
            this.originalComparer = originalComparer ?? throw new ArgumentNullException(nameof(originalComparer));
        }

        public bool Equals(T x, T y)
        {
            return originalComparer.Equals(x, y);
        }

        public int GetHashCode(T obj)
        {
            return originalComparer.GetHashCode(obj);
        }
    }
}

内容的提问来源于stack exchange,提问作者M. Johnstone

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 17:05:54