6

独自の IComparer を使用してリストを並べ替えると、アプリケーション (XNA ゲーム) を 1 時間以上実行しても問題なく動作します。しかし、突然、カスタム 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;
    }

例外のスクリーンショットは次のとおりです。

タイプ 'System.ArgumentException' の未処理の例外が mscorlib.dll で発生しました

Locals/Stack-Trace の詳細 (これは古いスクリーンショットですが、トレースを拡張できるように、数時間以内にこの例外を再現しようとします):

ここに画像の説明を入力

4

3 に答える 3

5

問題は、IComparer の実装です。一貫性のない結果が返される可能性があるため、並べ替え関数は例外をスローします。

詳細については、thisthis questionをご覧ください。

質問:

プロパティcontinent.Economy.CurrentDemandcontinent.Economy.CurrentPrice副作用はありませんか?

備考:

IComparer はnullを処理できる必要があります。ドキュメントから:

null は任意の型と比較でき、IComparable を使用する場合は例外が生成されません。並べ替えの際、null は他のどのオブジェクトよりも小さいと見なされます。

浮動小数点の問題かもしれませんが、それは単なる推測です。したがって、decimal代わりに を使用する必要がありfloatます。

于 2012-06-08T12:12:13.900 に答える
0

これは、Steve (XNA フォーラムから) から得た別の回答です。

どうやらこれは、両方のオブジェクトが同じであるために 0 を返さない場合に発生する可能性があります。両方が同じオブジェクトを参照している場合、GetCostCovering(c1) が GetCostCovering(c2) と等しくない可能性はありますか?

安全のために、 if (c1 == c2) return 0; を入れてみてください。Compare メソッドの開始時に、それがどのように機能するかを確認します。

どうもありがとうスティーブ!

于 2012-06-08T21:11:28.687 に答える
-1

私が正しく覚えていれば、最初の引数が2番目の引数よりも小さい場合、IComparer.Compareはゼロ未満を返すはずです。あなたはあなたの実装で反対のことをしているようです、それは例外を説明するでしょう。この失敗の前になぜそれが長い間働いていたのか説明できません...

于 2012-06-08T11:54:52.103 に答える