Anyone know a good workaround for the lack of an enum generic constraint?

What I want to do is something like this: I have enums with combined flagged values.

public static class EnumExtension
{
    public static bool IsSet<T>( this T input, T matchTo ) 
        where T:enum //the constraint I want that doesn't exist in C#3
    {    
        return (input & matchTo) != 0;
    }
}

So then I could do:

MyEnum tester = MyEnum.FlagA | MyEnum.FlagB

if( tester.IsSet( MyEnum.FlagA ) )
    //act on flag a

Unfortunately C#'s generic where constraints have no enum restriction, only class and struct. C# doesn't see enums as structs (even though they are value types) so I can't add extension types like this.

Anyone know a workaround?


EDIT: This is now live in version 0.0.0.2 of UnconstrainedMelody.

(As requested on my blog post about enum constraints. I've included the basic facts below for the sake of a standalone answer.)

The best solution is to wait for me to include it in UnconstrainedMelody1. This is a library which takes C# code with "fake" constraints such as

where T : struct, IEnumConstraint

and turns it into

where T : struct, System.Enum

via a postbuild step.

It shouldn't be too hard to write IsSet ... although catering for both Int64 -based and UInt64 -based flags could be the tricky part. (I smell some helper methods coming on, basically allowing me to treat any flags enum as if it had a base type of UInt64 .)

What would you want the behaviour to be if you called

tester.IsSet(MyFlags.A | MyFlags.C)

? Should it check that all the specified flags are set? That would be my expectation.

I'll try to do this on the way home tonight... I'm hoping to have a quick blitz on useful enum methods to get the library up to a usable standard quickly, then relax a bit.

EDIT: I'm not sure about IsSet as a name, by the way. Options:

  • Includes
  • Contains
  • HasFlag (or HasFlags)
  • IsSet (it's certainly an option)
  • Thoughts welcome. I'm sure it'll be a while before anything's set in stone anyway...


    1 or submit it as a patch, of course...


    Darren,如果这些类型是特定的枚举,那么这将起作用 - 对于一般的枚举工作,您必须将它们转换为整数(或更可能是uint)来执行布尔运算:

    public static bool IsSet( this Enum input, Enum matchTo )
    {
        return ( Convert.ToUInt32( input ) & Convert.ToUInt32( matchTo ) ) != 0;
    }
    

    Actually, it is possible, with an ugly trick. However, it cannot be used for extension methods.

    public abstract class Enums<Temp> where Temp : class {
        public static TEnum Parse<TEnum>(string name) where TEnum : struct, Temp {
            return (TEnum)Enum.Parse(typeof(TEnum), name); 
        }
    }
    public abstract class Enums : Enums<Enum> { }
    
    Enums.IsSet<DateTimeKind>("Local")
    

    If you want to, you can give Enums<Temp> a private constructor and a public nested abstract inherited class with Temp as Enum , to prevent inherited versions for non-enums.

    链接地址: http://www.djcxy.com/p/9222.html

    上一篇: 我应该Dispose()DataSet和DataTable吗?

    下一篇: 任何人都知道缺乏枚举通用约束的一个很好的解决方法?