6

how do i handle Enums without using switch or if statements in C#?

For Example

enum Pricemethod
{
    Max,
    Min,
    Average
}

... and i have a class Article

 public class Article 
{
    private List<Double> _pricehistorie;

    public List<Double> Pricehistorie
    {
        get { return _pricehistorie; }
        set { _pricehistorie = value; }
    }

    public Pricemethod Pricemethod { get; set; }

    public double Price
    {
        get {
            switch (Pricemethod)
            {
                case Pricemethod.Average: return Average();
                case Pricemethod.Max: return Max();
                case Pricemethod.Min: return Min();
            }

        }
    }

}

i want to avoid the switch statement and make it generic.

For a specific Pricemethod call a specific Calculation and return it.

get { return CalculatedPrice(Pricemethod); }

Wich pattern is to use here and maybe someone have a good implementation idea. Searched already for state pattern, but i dont think this is the right one.

slopsucker
  • 125
  • 2
  • 9

2 Answers2

12

how do I handle enums without using switch or if statements in C#?

You don't. enums are just a pleasant syntax for writing const int.

Consider this pattern:

public abstract class PriceMethod
{
  // Prevent inheritance from outside.
  private PriceMethod() {}

  public abstract decimal Invoke(IEnumerable<decimal> sequence);

  public static PriceMethod Max = new MaxMethod();

  private sealed class MaxMethod : PriceMethod
  {
    public override decimal Invoke(IEnumerable<decimal> sequence)
    {
      return sequence.Max();
    }
  }

  // etc, 
}

And now you can say

public decimal Price
{
    get { return PriceMethod.Invoke(this.PriceHistory); }
}

And the user can say

myArticle.PriceMethod = PriceMethod.Max;
decimal price = myArticle.Price;
Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • Marked this as the correct answer because of the overall learning from eric in this post! – slopsucker Oct 22 '13 at 17:43
  • This looks like the strategy design pattern. – Brian Oct 22 '13 at 19:32
  • @Brian: If "make an object that has a method that does what you want" is called "the strategy pattern" by pattern aficionados, then sure, this is the strategy pattern. Since there is only one of each, it's also the singleton pattern. It might also be the factory pattern. And perhaps several other patterns as well. I can't keep them all straight. – Eric Lippert Oct 22 '13 at 19:46
  • @Eric: My motivation in bringing up the strategy design pattern was to provide keywords that the OP may find useful for future research. Based on the acceptance of your answer, I believe slopsucker may find reading about this design pattern to be helpful. – Brian Oct 22 '13 at 19:52
5

You could create an interface, and classes that implement it:

public interface IPriceMethod
{
    double Calculate(IList<double> priceHistorie);
}
public class AveragePrice : IPriceMethod
{
    public double Calculate(IList<double> priceHistorie)
    {
        return priceHistorie.Average();
    }
}
// other classes
public class Article 
{
    private List<Double> _pricehistorie;

    public List<Double> Pricehistorie
    {
        get { return _pricehistorie; }
        set { _pricehistorie = value; }
    }

    public IPriceMethod Pricemethod { get; set; }

    public double Price
    {
        get {
            return Pricemethod.Calculate(Pricehistorie);
        }
    }

}

Edit: another way is using a Dictionary to map Funcs, so you don't have to create classes just for this (this code is based on code by Servy, who since deleted his answer):

public class Article
{
    private static readonly Dictionary<Pricemethod, Func<IEnumerable<double>, double>>
        priceMethods = new Dictionary<Pricemethod, Func<IEnumerable<double>, double>>
        {
            {Pricemethod.Max,ph => ph.Max()},
            {Pricemethod.Min,ph => ph.Min()},
            {Pricemethod.Average,ph => ph.Average()},
        };

    public Pricemethod Pricemethod { get; set; }
    public List<Double> Pricehistory { get; set; }

    public double Price
    {
        get
        {
            return priceMethods[Pricemethod](Pricehistory);
        }
    }
}
Community
  • 1
  • 1
Tim S.
  • 55,448
  • 7
  • 96
  • 122
  • Looks good, and works. Tahnk you! But isn't there a smarter way instead of implementing tons of classes which have 1 method? – slopsucker Oct 22 '13 at 17:41
  • @slopsucker I've added an example of that. – Tim S. Oct 22 '13 at 17:49
  • I still like the Interface solution better. If you need to add new calculation methods in the future you don't need to touch your Article class. Yes you'll end up with more classes but it will be more isolated and easier to maintain I think. The second solution is almost the same as having your switch and Enums. – Adolfo Perez Oct 23 '13 at 12:38
  • in Article class "public Pricemethod Pricemethod { get; set; }" should use the interface IPricemethod "public IPricemethod Pricemethod { get; set; }" – Roni Axelrad Sep 27 '18 at 14:09