0

我的代码中有一个用于集合的排序方法,今天我发现了一些奇怪的东西。当我尝试向枚举添加新的枚举值时,排序方法因此错误而崩溃。

无法排序,因为 IComparer.Compare() 方法返回不一致的结果。一个值与自身比较不相等,或者一个值与另一个值重复比较会产生不同的结果。x:'',x 的类型:'Texture2D',IComparer:'System.Array+FunctorComparer`1[Microsoft.Xna.Framework.Graphics.Texture2D]'。

这看起来真的很奇怪,现在排序依赖于早期结果,它应该做的就是在枚举索引之后排序,而不是字母顺序。

这是代码。

    availableTiles.Sort(CompareTilesToEnum);

    private static int CompareTilesToEnum(Texture2D x, Texture2D y)
    {
        int xValue = (int) (Enum.Parse(typeof(TileTyp), x.Name, true));
        int yValue = (int) (Enum.Parse(typeof(TileTyp), y.Name, true));
        if (xValue > yValue)
        {
            return 1;
        }
        else
        {
            return -1;
        }
    }

    public enum TileTyp
    {
        Nothing = -1,
        Forest,
        Grass,
        GrassSandBottom,
        GrassSandLeft,
        GrassSandRight,
        GrassSandTop,
        Mounten,
        Sand,
        Snow,
        Water,
        GrassSandTopLeft,
        GrassSandAll,
        GrassSandBottomLeft,
        GrassSandBottomRightLeft,
        GrassSandBottomRightTop,
        GrassSandBottomTopLeft,
        GrassSandRightLeft,
        GrassSandRightTop,
        GrassSandRightTopLeft,
        GrassSandBottomRight,
        GrassSandBottomTop
    }

我添加的值是

    GrassSandBottomRight,
    GrassSandBottomTop
4

3 回答 3

4

您的比较永远不会返回 0 - 即使值相等。你有什么理由不只是要求int.CompareTo比较这些值吗?

private static int CompareTilesToEnum(Texture2D x, Texture2D y)
{
    int xValue = (int) (Enum.Parse(typeof(TileTyp), x.Name, true));
    int yValue = (int) (Enum.Parse(typeof(TileTyp), y.Name, true));
    return xValue.CompareTo(yValue);
}

更简单,更重要的是,它应该实际工作:)

于 2012-08-26T20:04:03.077 回答
1

正如错误明确指出的那样,您的比较器已损坏。

0如果值相等,则需要返回。

于 2012-08-26T20:03:58.483 回答
1

任何比较方法都必须遵循一些规则:

  1. 如果 A == B,则 B == A(两次都返回零)。
  2. 如果 A < B 且 B < C,则 A < C。
  3. 如果 A < B,则 B > A
  4. A == A(如果与自身比较,则返回零)。

(注意,==上面的意思是既不是<也不>是真的。允许两个对象在排序顺序中是等价的,而不是对应的Equals。我们可以有一个规则,将所有包含数字的字符串按数字顺序排序,把所有其他字符串和结尾,但不关心其他字符串的顺序)。

这些规则适用于任何语言(它们不是编程规则,它们是逻辑规则),也有一个特定于 .NET 的规则:

5:如果 A != null,则 A > null。

你违反了前四个规则。由于Texture2D是引用类型,因此您也有违反规则 5 的风险(尽管会引发不同的异常)。

你也很幸运 .NET 抓住了它。不同的排序算法很可能会因更令人困惑的错误而崩溃或陷入无限循环,因为它例如发现项目 6 被报告为大于项目 7 并交换它们,然后很快发现项目 6 被报告为大于项目7和交换了它们,然后很快就找到了......

private static int CompareTilesToEnum(Texture2D x, Texture2D y)
{
    //Let's deal with nulls first
    if(ReferenceEquals(x, y))//both null or both same item
      return 0;
    if(x == null)
      return -1;
    if(y == null)
      return 1;
    //Enum has a CompareTo that works on integral value, so why not just use that?
    return Enum.Parse(typeof(TileTyp), x.Name, true)).CompareTo(Enum.Parse(typeof(TileTyp), y.Name, true)));
}

(这假设解析失败是不可能的,并且不必考虑)。

于 2012-08-26T21:47:18.220 回答