7

I am just starting with Generics in C# but have run into a problem early on, how can I call .HasFlag() on a generic Enum?

public class Example<TEnum> where TEnum : struct {
}

How can I add the [Flags] attribute to it?

DevDave
  • 6,700
  • 12
  • 65
  • 99
  • 1
    In short, you can't. Constraints do not consider attributes on the generic parameters. You'd have to enforce it through reflection. – M.Babcock Mar 01 '12 at 16:07
  • 1
    Type parameters are supposed to start with `T`; you should change `GenericEnum` to `TEnum`. – SLaks Mar 01 '12 at 16:08
  • could you give an example @M.Babcock? and duly noted, @SLaks – DevDave Mar 01 '12 at 16:11
  • 1
    Also you can use [John Skeet's library](http://msmvps.com/blogs/jon_skeet/archive/2009/09/11/1722426.aspx) to enforce enum constraint if you like. – Raj Ranjhan Mar 01 '12 at 16:35
  • @AnuragRanjhan the library link above returns a 404 error. Could you please update? – kmoormann Nov 11 '16 at 04:17

1 Answers1

8

Calling the instance method will require boxing anyway, so, since you can't constrain to Enum, just abandon generics and use Enum. For example, instead of:

void Something(TEnum enumValue, TEnum flags)
{
    if (enumValue.HasFlags(flags))
        //do something ...
}

Do this:

void Something(Enum enumValue, Enum flags)
{
    if (enumValue.HasFlags(flags))
        //do something ...
}

In a generic method, you could achieve your goal like this:

void Something(TEnum enumValue, TEnum flags)
{
    Enum castValue = (Enum)(object)enumValue;
    Enum castFlags = (Enum)(object)flags;

    if (castValue.HasFlags(castFlags))
        //do something ...
}

This will throw an exception at runtime if you call the method with a value type that isn't an enum. You could also cast via ValueType rather than object, since the type parameter is known to represent a value type:

Enum castValue = (Enum)(ValueType)enumValue;
phoog
  • 42,068
  • 6
  • 79
  • 117
  • I was doing what you were suggesting initially, but am trying to refactor several methods that use your example into one that will take a generic enum and still be able to call has flags on it – DevDave Mar 01 '12 at 16:16
  • 2
    @Tyler I added an example showing how you can cast an instance of a generic type parameter to `Enum`. – phoog Mar 01 '12 at 16:20
  • thanks @phoog. am still trying to work it out but have noticed that the HasFlag() method has appeared in intellisense! – DevDave Mar 01 '12 at 16:27
  • 1
    @Tyler you're welcome. Also note that the `HasFlags` method will work even if your type argument is an enum that doesn't have the `Flags` attribute. If you want to prevent calling HasFlags on a non-flags enum, you'll need to do a runtime check using reflection. If you perform that check in the static constructor of your class, it will have virtually no impact on performance. – phoog Mar 01 '12 at 16:31