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

Console App与Excel DNA中IComparer使用结果不一致问题排查

Excel DNA UDF锯齿状排序异常原因解析

我使用Excel DNA开发可在Excel中调用的UDF,通过C#的IComparer实现特殊的锯齿状排序,相同代码在Console App中运行完全正常,但在Excel环境下运行时,结果出现值填充所有行列的异常状态。调试发现,部分视觉上完全相同的值(如"A"),使用==判断时返回false,直接导致逻辑异常。

问题代码

using System;
using System.Linq;
using System.Collections.Generic;

namespace Clxn
{
    public static class fComparer
    {
        static void Main(string[] args)
        {
            object[,] MainRange =
            {
                { "c", "E", "B" },
                { "b", "A", "B" },
                { "A", "D", "D" },
                { "F", "D", "C" }
            };

            int Cntr = 0;
            object[] SortingKey = (from object x in MainRange select x).ToArray();
            object[,] Rxlt = new object[SortingKey.Length, MainRange.GetLength(1) + 1];

            for (int xCol = 0; xCol < Rxlt.GetLength(1); xCol++)
            {
                Cntr = 0;
                for (int xRow = 0; xRow < Rxlt.GetLength(0); xRow++)
                {
                    if (xCol == 0) { Rxlt[xRow, 0] = SortingKey.OrderBy(x => x, new fxl_ComparerObjects()).ToArray()[(Rxlt.GetLength(0) * (xCol)) + xRow]; }
                    else
                    {
                        object[] OrderedSlice = SlicedColumn(MainRange, xCol - 1).ToArray().OrderBy(f => f, new fxl_ComparerObjects()).ToArray();
                        if (Rxlt[xRow, 0] == OrderedSlice[Cntr]) { Rxlt[xRow, xCol] = OrderedSlice[Cntr]; Cntr++; }
                    }
                    if (Cntr >= MainRange.GetLength(0)) Cntr = 0;
                }
            }

            for (int xRow = 0; xRow < Rxlt.GetLength(0); xRow++)
            {
                for (int xCol = 0; xCol < Rxlt.GetLength(1); xCol++) { Console.Write(Rxlt[xRow, xCol] + "\t"); }
                Console.WriteLine("");
            }
        }

        internal static IEnumerable<T> SlicedColumn<T>(this T[,] array, int column)
        {
            for (var i = array.GetLowerBound(0); i <= array.GetUpperBound(0); i++) { yield return array[i, column]; }
        }

        internal class fxl_ComparerObjects : IComparer<object>
        {
            public int SorterIndex { get; set; }
            public int Compare(object x, object y)
            {
                double xVal, yVal;
                var xIsVal = double.TryParse(x.ToString(), out xVal);
                var yIsVal = double.TryParse(y.ToString(), out yVal);
                if (xIsVal && yIsVal) return xVal.CompareTo(yVal);
                if (!xIsVal && !yIsVal) return x.ToString().CompareTo(y.ToString());
                if (xIsVal) return -1;
                return 1;
            }
        }
    }
}

异常原因

1. 环境对象类型差异

Console App中使用的是原生.NET对象(字符串、数值都是CLR内置类型),==对于值类型直接比较值,对于字符串则因为字符串池的存在,相同内容的字符串会指向同一引用,==能正确判断内容相等。

但在Excel环境中,传递给UDF的对象是Excel COM对象的包装实例,哪怕内容完全相同,它们也是不同的引用对象。此时用==比较的是对象的引用地址,而非实际内容,自然会返回false。

2. 直接触发逻辑异常

代码中Rxlt[xRow, 0] == OrderedSlice[Cntr]这一行的判断逻辑,因为引用比较失败,导致后续的填充代码无法执行,最终出现值填充所有行列的异常。

修复方案

替换基于引用的==判断,改为基于内容的比较:

  • 方案一:使用字符串内容比较
    if (string.Equals(Rxlt[xRow, 0]?.ToString(), OrderedSlice[Cntr]?.ToString(), StringComparison.Ordinal))
    
  • 方案二:复用现有Comparer逻辑
    直接调用你已经实现的fxl_ComparerObjects中的Compare方法,判断返回值是否为0(代表两个对象逻辑相等):
    var comparer = new fxl_ComparerObjects();
    if (comparer.Compare(Rxlt[xRow, 0], OrderedSlice[Cntr]) == 0)
    

内容的提问来源于stack exchange,提问作者Faraz Ahmed Qureshi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 03:10:03