Comparison with a range I'm developing a class to compare prices. For example, give me products which price are above 50 or under 50. Here's my API:

var indicator = new PriceIndicator(PriceComparison.Above, 50);
var actual = indicator.Apply(listOfProductPrices);  


I managed to design my code for the operator Above and Under comparison:

public abstract class PriceComparison
{
    public static readonly UnderPriceComparison Under = new UnderPriceComparison();

    public static readonly AbovePriceComparison Above = new AbovePriceComparison();

    public abstract bool Evaluate(double price, double valueToCompare);
}

public class AbovePriceComparison : PriceComparison
{
    public override bool Evaluate(double price, double valueToCompare)
    {
        return price &gt; valueToCompare;
    }
}

public class UnderPriceComparison : PriceComparison
{
    public override bool Evaluate(double price, double valueToCompare)
    {
        return price &lt; valueToCompare;
    }
}


public class PriceIndicator : IBuyIndicator
{
    private readonly PriceComparison _comparison;
    private readonly int _value;

    public PriceIndicator(PriceComparison comparison, int value) 
    {
        _comparison = comparison;
        _value = value;
    }


    public IList&lt;BuyOrder&gt; Apply(IList&lt;int&gt; productPrices)
    {
        return productPrices.Where(price =&gt; _comparison.Evaluate(price, _value))
                            .Select(b =&gt; new BuyOrder(b))
                            .ToList();
    }
}


Now, I want to manage Range price. I want my API to look as simple as the one above. Ideally, it would be

var indicator = new PriceIndicator(PriceComparison.Range, 50, 100); // Here's the change
var actual = indicator.Apply(listOfProductPrices);  


I don't know how I can design this. What I tried to do so far is to add another Evaluate method in PriceComparison, which takes three parameters: double price, double left, double right.  But then, my previous two methods have to implement it and will have to throw IncorrectComparisonException because they can only compare with one value. So I'm not really fan of this design.
Here you go. I made Range inclusive only, but it's easy to modify. I also extracted a few interfaces for easy unit testing and use IEnumerable&lt;T&gt; instead of IList&lt;T&gt;.

public interface IPriceComparison
{
    bool Evaluate(decimal price, params decimal[] valuesToCompare);
}

public abstract class PriceComparison : IPriceComparison
{
    private static readonly IPriceComparison under = UnderPriceComparison.Create();

    private static readonly IPriceComparison above = AbovePriceComparison.Create();

    private static readonly IPriceComparison range = RangePriceComparison.Create();

    public static IPriceComparison Under
    {
        get
        {
            return under;
        }
    }

    public static IPriceComparison Above
    {
        get
        {
            return above;
        }
    }

    public static IPriceComparison Range
    {
        get
        {
            return range;
        }
    }

    public abstract bool Evaluate(decimal price, params decimal[] valuesToCompare);
}

public sealed class AbovePriceComparison : PriceComparison
{
    private AbovePriceComparison()
    {
    }

    public static IPriceComparison Create()
    {
        return new AbovePriceComparison();
    }

    public override bool Evaluate(decimal price, params decimal[] valuesToCompare)
    {
        return (valuesToCompare == null) || (valuesToCompare.Length != 1) || (price &gt; valuesToCompare[0]);
    }
}

public sealed class UnderPriceComparison : PriceComparison
{
    private UnderPriceComparison()
    {
    }

    public static IPriceComparison Create()
    {
        return new UnderPriceComparison();
    }

    public override bool Evaluate(decimal price, params decimal[] valuesToCompare)
    {
        return (valuesToCompare == null) || (valuesToCompare.Length != 1) || (price &lt; valuesToCompare[0]);
    }
}

public sealed class RangePriceComparison : PriceComparison
{
    private RangePriceComparison()
    {
    }

    public static IPriceComparison Create()
    {
        return new RangePriceComparison();
    }

    public override bool Evaluate(decimal price, params decimal[] valuesToCompare)
    {
        return (valuesToCompare == null)
            || (valuesToCompare.Length != 2)
            || ((price &gt; valuesToCompare[0]) &amp;&amp; (price &lt; valuesToCompare[1]));
    }
}

public interface IBuyOrder
{
    int Price
    {
        get;
    }
}

public sealed class BuyOrder : IBuyOrder
{
    private readonly int price;

    private BuyOrder(int price)
    {
        this.price = price;
    }

    public static IBuyOrder Create(int price)
    {
        return new BuyOrder(price);
    }

    public int Price
    {
        get
        {
            return this.price;
        }
    }
}

public interface IBuyIndicator
{
    IEnumerable&lt;IBuyOrder&gt; Apply(IEnumerable&lt;int&gt; productPrices);
}

public sealed class PriceIndicator : IBuyIndicator
{
    private readonly IPriceComparison comparison;

    private readonly decimal[] values;

    private PriceIndicator(IPriceComparison comparison, params decimal[] values)
    {
        if (comparison == null)
        {
            throw new ArgumentNullException("comparison");
        }

        this.comparison = comparison;
        this.values = values;
    }

    public static IBuyIndicator Create(IPriceComparison comparison, params decimal[] values)
    {
        return new PriceIndicator(comparison, values);
    }

    public IEnumerable&lt;IBuyOrder&gt; Apply(IEnumerable&lt;int&gt; productPrices)
    {
        return productPrices.Where(price =&gt; this.comparison.Evaluate(price, this.values))
            .Select(BuyOrder.Create)
            .ToList();
    }
}