我用自己的IComparer对List进行排序,这在运行应用程序(XNA游戏)一个多小时后效果很好。但是,突然间,我在使用自定义Comparer调用sort-method时有时会出现以下错误:
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;
}
此处是例外的屏幕截图:
这里仔细看看Locals / Stack-Trace(这是一个旧截图,但我会尝试在接下来的几个小时内重现这个异常,以便我可以扩展跟踪):
答案 0 :(得分:5)
问题是你的IComparer的实现。它可以返回不一致的结果,因此sort函数将抛出异常。
如果您需要了解更多信息,请查看this和this question。
问题:
属性continent.Economy.CurrentDemand
和continent.Economy.CurrentPrice
是否没有副作用?
说明:
您的IComparer应该能够处理 null 。来自docs:
允许将null与任何类型进行比较,并且不生成 使用IComparable时的异常。排序时,考虑null 比任何其他物体都少。
也许这是一个浮点问题,但这只是一个疯狂的猜测。因此,您可以使用decimal
代替float
。
答案 1 :(得分:0)
这是我从Steve(来自XNA论坛)得到的另一个答案:
显然,如果两个对象不相同,则返回0时会发生这种情况。 GetCostCovering(c1)在引用同一个对象的任何时候都有可能不等于GetCostCovering(c2)吗?
为安全起见,尝试将if(c1 == c2)返回0;在比较方法的开头,看看它是如何工作的。
非常感谢史蒂夫!
答案 2 :(得分:-1)
如果我没记错的话,如果第一个参数小于第二个参数,IComparer.Compare应该返回小于零。您似乎在实现中执行了相反的操作,这可以解释异常。我无法解释为什么它在失败之前已经工作了很长时间......