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
相关产品推荐
相关产品推荐

