Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I get a System.ArgumentException when invoking Sort(IComparer) on a List?

I sort a List with my own IComparer and this works just fine when running the application (XNA game) for more than an hour. But then, suddenly, I sometimes get the following error when invoking the sort-method with my custom Comparer:

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

This is the line where the exception is thrown:

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

and this is my class implementing IComparer interface:

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; 
        } 
    } 

} 

Here some methods that are linked to the comparer...:

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;
    }

Here the screenshot of the exception:

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

Here a closer look of the Locals/Stack-Trace (this is an old screenshot, but I will try to reproduce this exception within the next hours, so that I can expand the trace):

enter image description here

like image 660
salocinx Avatar asked Jun 08 '12 11:06

salocinx


1 Answers

The problem is your implementation of your IComparer. It can return inconsistent results, so the sort function will throw an exception.

Maybe have a look at this and this question for more information.

Question:

Are the properties continent.Economy.CurrentDemand and continent.Economy.CurrentPrice free of side effects?

Remarks:

Your IComparer should be able to handle null. From the docs:

Comparing null with any type is allowed and does not generate an exception when using IComparable. When sorting, null is considered to be less than any other object.

Maybe it is an floating point issue, but that's just a wild guess. So maybe you should use decimal instead of float.

like image 156
sloth Avatar answered Sep 30 '22 18:09

sloth