MaddEye
MaddEye

Reputation: 751

C# List OrderBy creates an OutOfMemory Error

I tried to Sort an List by an property which i get dynamiclly. When i run my code with Strength on first position and Range on second i get an OutOfMemory Error, but when i change the order everything works fine.

Code:

public enum EffectType
{
    Duration,
    Efficiency,
    Range,
    Strength
}

public List<Modlist> Sort(List<EffectType> filter) {
    return ComboList.OrderByDescending(
        x => x.GetType()
            .GetProperty(filter[0].ToString())
            .GetValue(x, null))
    .ThenByDescending(
        y => y.GetType()
            .GetProperty(filter[1].ToString())
            .GetValue(y, null))
    .ToList();
}

public class Modlist
{
    public List<Mod> Mods { get; set; }
    public float Strength { get; set; }
    public float Range { get; set; }
    public float Duration { get; set; }
    public float Efficiency { get; set; }
}

I can't find the error and searched for days now.

Upvotes: 0

Views: 110

Answers (1)

Aleks Andreev
Aleks Andreev

Reputation: 7054

Reflection is slow, so try avoid it if it's possible.
You can achieve the same effect with value selectors like this:

return ComboList
    .OrderByDescending(x => x.Duration)
    .ToList();

In your case you may create a dictionary of selectors like this:

private readonly Dictionary<EffectType, Func<Modlist, float>> selectors
    = new Dictionary<EffectType, Func<Modlist, float>>
{
  { EffectType.Duration, m => m.Duration },
  { EffectType.Efficiency, m => m.Efficiency },
  { EffectType.Range, m => m.Range },
  { EffectType.Strength, m => m.Strength }
};

And then convert your enum items into selectors and use them:

public List<Modlist> Sort(List<EffectType> filters)
{
    if (filters.Count < 1) // no sort is required
        return ComboList;

    var currentSelectors = filters
        .Select(f => selectors[f])
        .ToArray();

    var sorted = ComboList.OrderByDescending(currentSelectors[0]);
    for (var i = 1; i < currentSelectors.Length; ++i)
        sorted = sorted.ThenByDescending(currentSelectors[i]);

    return sorted.ToList();
}

Upvotes: 1

Related Questions