【问题标题】:Array.Sort with Custom IComparer InterfaceArray.Sort 与自定义 IComparer 接口
【发布时间】:2014-02-14 16:16:17
【问题描述】:

我编写了以下实现 IComparer 的类:

class CustomComparer : IComparer<string>
{
    public int Compare(string x, string y)
    {
        int intX;
        int intY;

        if (int.TryParse(x, out intX) && int.TryParse(y, out intY)) //both numbers
        {
            intX.CompareTo(intY);
        }
        else if (!int.TryParse(x, out intX) && !int.TryParse(y, out intY)) //both letters
        {
            x.CompareTo(y);
        }
        else if (!int.TryParse(x, out intX) && int.TryParse(y, out intY)) //first is a letter, second a number
        {
            return -1;
        }
        else if (int.TryParse(x, out intX) && !int.TryParse(y, out intY)) //first is a number, second is a letter
        {
            return 1;
        }

        return 0;
    }
}

我不确定我是否做对了所有事情,但我目前无法调用它。在我的程序中,我有一个 ArrayList 我正在尝试调用它:

CustomComparer c = new CustomComparer()
myArrayList.Sort(c);

我做错了什么?

【问题讨论】:

    标签: c# sorting arraylist icomparer


    【解决方案1】:

    我做错了什么?

    你至少做错了七件事。

    首先,您缺少两个 return 语句。

    其次,由于您没有注意到您缺少两个 return 语句,因此您很可能缺少将执行这些代码路径的测试用例。

    第三,干燥你的代码。不要重复自己。重写此代码,以便您调用int.TryParse 两次,而不是八次。

    第四,永远不要在之后编写的代码中使用ArrayList,比如2005年。使用List&lt;string&gt;

    第五,return 0 不可达。无法访问的代码是一种不好的做法。重写方法,让每一行都可达。

    第六,ArrayList.Sort 不接受IComparer&lt;string&gt;

    第七,比较器需要处理空值。明确处理这些情况是个好主意,这样您就不会意外取消引用它们。传统上要走的路是说空值比其他任何东西都小。

    第八,虽然返回任何旧数字并没有错误,但我在编写比较器时始终返回 0、1 或 -1 是我的习惯。

    第九,在字符串引用相等的情况下,“提前退出”是一个好习惯。这种情况非常快,所以如果你能接受,你应该这样做。

    我倾向于这样写代码:

    static int? MyParse(string s)
    {
        int parsed;
        bool isValid = int.TryParse(s, out parsed);
        return isValid ? (int?)parsed : (int?) null;
    }
    public int Compare(string x, string y)
    {
        if (ReferenceEquals(x, y)) return 0;
        if (ReferenceEquals(x, null)) return -1;
        if (ReferenceEquals(y, null)) return 1;
    
        // We now know that neither is null.
    
        int? intX = MyParse(x);
        int? intY = MyParse(y);
    
        if (!intX.HasValue && intY.HasValue) return -1;
        if (intX.HasValue && !intY.HasValue) return 1;
    
        // We now know that intX.HasValue == intY.HasValue
    
        int result = intX.HasValue ? intX.Value.CompareTo(intY.Value) : x.CompareTo(y);
        if (result < 0) return -1;
        if (result > 0) return 1;
        return 0;
    }
    

    【讨论】:

    • 您决定不直接返回结果变量而不是检查 1/-1 的任何特殊原因?
    • @solutionyogi 我更喜欢实施更严格的合同版本。我觉得奇怪的是,一个三值函数可以合法地返回 40 亿个值。
    【解决方案2】:

    ArrayList 是非泛型集合,它需要非泛型 IComparer 作为 Sort 方法参数。

    您应该将集合更改为通用集合,例如List&lt;string&gt;string[],或者实现IComparer 而不是IComparer&lt;string&gt;

    【讨论】:

      【解决方案3】:

      compareTo之后的前两个if条件中也使用return

      【讨论】:

      • 是的,没注意到,现在排序。谢谢。
      【解决方案4】:

      问题在于您使用的是非泛型集合ArrayList。它的Sort() 方法需要一个非通用比较器,而不是通用比较器。而且由于泛型IComparer&lt;T&gt; 接口不是从非泛型IComparer 派生的,因此将其传递是行不通的。

      相反,实现比较器应该从通用Comparer&lt;T&gt; 类派生。此类实现了通用和非通用IComparer 接口,因此您只需实现一次比较。比较将转发给您的实际实施。这将允许您在需要通用或非通用版本时使用比较器。

      class CustomStringComparer : Comparer<string>
      {
          public override int Compare(string x, string y)
          {
              // ...
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-02-12
        • 1970-01-01
        • 2021-12-05
        • 1970-01-01
        • 1970-01-01
        • 2017-06-19
        • 2016-09-12
        相关资源
        最近更新 更多