Comparison of 2 values based on custom operator I am working on a library that parses query strings and evaluates the result for a given context. The query has the format FIELD OPERATOR VALUE (AND|OR) .... The list of operators is constant, but the field's type can be customized (default primary types are supported right now - other types can be added).

To enable the user of the library to overwrite the behavior of the operators, there is a FieldComparer class that evaluates 2 values for a given operator. It uses the default comparer of the type, but can be extended to provide specialized behavior.

The StringFieldComparer is such a specialized comparer for fields of type string. It adds support for wildcards and regex.

Operators

public enum Operator
{
    Equals,
    LessThen,
    LessThenOrEquals,
    GraterThan,
    GraterThanOrEquals,
    NotEquals,
    Matches,
    NotMatches,
}


FieldComparer

public class FieldComparer&lt;TFieldValue&gt;
{
    protected FieldComparer()
    { }

    public virtual bool Compare(Operator op, TFieldValue left, TFieldValue right)
    {
        var comparer = Comparer&lt;TFieldValue&gt;.Default;
        switch (op)
        {
            case Operator.Equals:
                return comparer.Compare(left, right) == 0;
            case Operator.NotEquals:
                return comparer.Compare(left, right) != 0;
            case Operator.GraterThan:
                return comparer.Compare(left, right) &lt; 0;
            case Operator.GraterThanOrEquals:
                return comparer.Compare(left, right) &lt;= 0;
            case Operator.LessThen:
                return comparer.Compare(left, right) &gt; 0;
            case Operator.LessThenOrEquals:
                return comparer.Compare(left, right) &gt;= 0;
            default:
                throw new NotSupportedException($"Operator '{op}' is not supported for type '{typeof(TFieldValue)}'");
        }
    }

    internal static FieldComparer&lt;TFieldValue&gt; Default { get; } = new FieldComparer&lt;TFieldValue&gt;();
}


StringFieldComparer

public class StringFieldComparer : FieldComparer&lt;string&gt;
{
    private readonly Dictionary&lt;string, Regex&gt; myRegexes = new Dictionary&lt;string, Regex&gt;();

    public override bool Compare(Operator op, string left, string right)
    {
        switch (op)
        {
            case Operator.Matches:
            case Operator.NotMatches:
                var regex = GetRegex(left);
                var match = regex.IsMatch(right);
                return op == Operator.Matches ? match : !match;
            case Operator.Equals:
            case Operator.NotEquals:
                regex = GetWildcardRegex(left);
                match = regex.IsMatch(right);
                return op == Operator.Equals ? match : !match;
            default:
                return base.Compare(op, left, right);
        }
    }

    private Regex GetWildcardRegex(string left)
    {
        var pattern = Regex.Escape(left)
            .Replace(@"\*", ".*")
            .Replace(@"\?", ".");

        pattern = "^" + pattern + "$";

        return GetRegex(pattern);
    }

    private Regex GetRegex(string left)
    {
        Regex regex;
        if (!myRegexes.TryGetValue(left, out regex))
        {
            regex = new Regex(left, RegexOptions.Compiled | RegexOptions.IgnoreCase);
            myRegexes.Add(left, regex);
        }
        return regex;
    }
}


Usage

var comparerStr = new StringFieldComparer();
comparerStr.Compare(Operator.Equals, "Hello*", "Hello World"); // true
comparerStr.Compare(Operator.Matches, "He.lo.*", "Hello World"); // true

var comparerInt = FieldComparer&lt;int&gt;.Default;
comparerInt.Compare(Operator.Equals, 1, 1); // true
comparerInt.Compare(Operator.LessThan, 1, 4); // false




I am not really happy with the method StringFieldComparer.Compare because the op will be checked twice for Equals/NotEquals and Match/NotMatch. Is there a way to realize it with only one check without creating the regex unnecessarily? 

As always, any feedback is welcome! :)
public class FieldComparer&lt;TFieldValue&gt;
{
  protected FieldComparer()
  { }
}



The right way to prevent a type from being created and allowing only derived types to do it is... to use an abstract class. By making the FieldComparer abstract you won't need to hide the default constructor.

An example implementation could look like this where you have a private class DefaultFieldComparer that implements the FieldComparer:

public abstract class FieldComparer&lt;TFieldValue&gt;
{
    ..

    internal static FieldComparer&lt;TFieldValue&gt; Default { get; } = new DefaultFieldComparer();

    private class DefaultFieldComparer : FieldComparer&lt;TFieldValue&gt; { }
}


I find this is a cleaner solution becasue it informs me that the FieldComparer is a base class and intended be subclassed becasue on its own it has no use but if it has, then it should be instantiable.




private readonly Dictionary&lt;string, Regex&gt; myRegexes = new Dictionary&lt;string, Regex&gt;();

private Regex GetRegex(string left)
{
  Regex regex;
  if (!myRegexes.TryGetValue(left, out regex))
  {
      regex = new Regex(left, RegexOptions.Compiled | RegexOptions.IgnoreCase);
      myRegexes.Add(left, regex);
  }
  return regex;
}



I'm not sure whether it's really necessary to use a dictionary for the regexes. In most cases the static Regex.IsMatch is sufficient and it already does the caching thing:


  The static IsMatch(String, String) method is equivalent to constructing a Regex object with the regular expression pattern specified by pattern and calling the IsMatch(String) instance method. This regular expression pattern is cached for rapid retrieval by the regular expression engine.