5

I want to create an IRouteConstraint that filters a value against possible values of an enum. I tried to google it for myself, but that didn't result in anything.

Any ideas?

tereško
  • 57,247
  • 24
  • 95
  • 149
Jaap
  • 2,942
  • 2
  • 28
  • 49

2 Answers2

11

This is what I came up with:

public class EnumRouteConstraint<T> : IRouteConstraint
  where T : struct
{

  private readonly HashSet<string> enumNames;

  public EnumRouteConstraint()
  {
    string[] names = Enum.GetNames(typeof(T));
    enumNames = new HashSet<string>(from name in names select name.ToLowerInvariant());
  }

  public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
  {
    return enumNames.Contains(values[parameterName].ToString().ToLowerInvariant());
  }
}

I think a HashSet will perform much better than Enum.GetNames on each Match. Also the use generics makes it look a bit more fluent when you use the constraint.

Unfortunately, where T : Enum is not allowed by the compiler.

Jaap
  • 2,942
  • 2
  • 28
  • 49
  • 2
    *Unfortunately, where T : Enum is not allowed by the compiler* This is true, but you can still try to enforce it at runtime. http://stackoverflow.com/a/2936591/242520 – ta.speot.is Jul 03 '13 at 05:54
  • 2
    The constructor Enum.GetNames(typeof(T)) throws an exception if T is not an enum: ArgumentException: Type provided must be an Enum. – Jaap Jul 03 '13 at 09:34
  • C# 7.3 adds the option to use T: enum. However it doesn't work as one might expect, see https://stackoverflow.com/questions/50218754/c-sharp-7-3-enum-constraint-why-cant-i-use-the-enum-keyword – Bernard Vander Beken Dec 05 '19 at 12:56
5

See this

Essentially, you need

  private Type enumType;

  public EnumConstraint(Type enumType)
  {
    this.enumType = enumType;
  }

  public bool Match(HttpContextBase httpContext, 
    Route route, 
    string parameterName,     
    RouteValueDictionary values, 
    RouteDirection routeDirection)
  {
    // You can also try Enum.IsDefined, but docs say nothing as to
    // is it case sensitive or not.
    return Enum.GetNames(enumType).Any(s => s.ToLowerInvariant() == values[parameterName].ToString());
  }
Chris
  • 3,282
  • 1
  • 31
  • 35
Anton Gogolev
  • 110,157
  • 37
  • 194
  • 282
  • on my blog too - http://mikemilleresq.wordpress.com/2010/03/12/starting-small-mvc-constraints/ – Mike Miller Jun 07 '11 at 09:43
  • `Enum.IsDefined()` is case sensitive, so should be avoided if your route constraint should work regardless of case. – Chris Apr 04 '14 at 11:23