6

我使用自己的 IComparer 对列表进行排序,并且在运行应用程序(XNA 游戏)超过一个小时时效果很好。但是,突然之间,在使用自定义比较器调用排序方法时,有时会出现以下错误:

An unhandled exception of type 'System.ArgumentException' occured in mscorlib.dll
Additional Information: ArgumentException

这是引发异常的行:

List<Continent> markets = new List<Continent>();
// filling the markets list ...
markets.Sort(new MarketCostCoverComparer(this)); 

这是我实现 IComparer 接口的类:

class MarketCostCoverComparer : IComparer<Continent> { 

    private Player player; 

    public MarketCostCoverComparer(Player player) { 
        this.player=player; 
    } 

    public int Compare(Continent c1, Continent c2) { 
        if(player.GetCostCovering(c1)<player.GetCostCovering(c2)) { 
            return +1; 
        } else if(player.GetCostCovering(c1)==player.GetCostCovering(c2)) { 
            return 0; 
        } else { 
            return -1; 
        } 
    } 

} 

这里有一些链接到比较器的方法......:

public float GetCostCovering(Continent continent) {
        // cover<1 => bad | cover>1 => good
        if(GetOilfieldTheoreticOutput(continent.Type, true)<continent.Economy.CurrentDemand) {
            return ((float)((GetOilfieldTheoreticOutput(continent.Type, true)*continent.Economy.CurrentPrice)))/(float)GetOilfieldCosts(continent.Type, true);
        } else {
            return ((float)((continent.Economy.CurrentDemand*continent.Economy.CurrentPrice)))/(float)GetOilfieldCosts(continent.Type, true);
        }
    }

public int GetOilfieldTheoreticOutput(ContinentType continent, bool drilled) {
        int total = 0;
        foreach(Oilfield oilfield in worldmap.Continents[(int)continent].Oilfields) {
            if(oilfield.Owner==this && oilfield.Drilled==drilled) {
                total+=oilfield.TheoreticOutput;
            }
        }
        return total;
    }

public int GetOilfieldCosts(ContinentType continent, bool drilled) {
        int total = 0;
        foreach(Oilfield oilfield in worldmap.Continents[(int)continent].Oilfields) {
            if(oilfield.Owner==this && oilfield.Drilled==drilled) {
                total+=oilfield.Costs;
            }
        }
        return total;
    }

这是异常的屏幕截图:

mscorlib.dll 中出现“System.ArgumentException”类型的未处理异常

这里仔细看看 Locals/Stack-Trace(这是一个旧的屏幕截图,但我会在接下来的几个小时内尝试重现这个异常,以便我可以展开跟踪):

在此处输入图像描述

4

3 回答 3

5

问题是您的 IComparer 的实现。它可以返回不一致的结果,所以排序函数会抛出异常。

也许看看这个这个问题以获取更多信息。

问题:

特性continent.Economy.CurrentDemandcontinent.Economy.CurrentPrice无副作用吗?

评论:

您的 IComparer 应该能够处理null。从文档

允许将 null 与任何类型进行比较,并且在使用 IComparable 时不会生成异常。排序时,null 被认为小于任何其他对象。

也许这是一个浮点问题,但这只是一个疯狂的猜测。所以也许你应该使用decimal而不是float.

于 2012-06-08T12:12:13.900 回答
0

这是我从史蒂夫(来自 XNA 论坛)那里得到的另一个答案:

显然,当您不为两个相同的对象返回 0 时,可能会发生这种情况。当它们都引用同一个对象时,GetCostCovering(c1) 是否有可能在任何时候都不等于 GetCostCovering(c2)?

为了安全起见,试着把 if (c1 == c2) return 0; 在 Compare 方法的开头,看看效果如何。

非常感谢史蒂夫!

于 2012-06-08T21:11:28.687 回答
-1

如果我没记错的话,如果第一个参数小于第二个参数,IComparer.Compare 应该返回小于零。您在实现中似乎做了相反的事情,这可以解释异常。我无法解释为什么它在这次失败之前工作了很长时间......

于 2012-06-08T11:54:52.103 回答