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

后端 未结 12 1294
情书的邮戳
情书的邮戳 2020-11-22 15:37

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

public static class EnumExtension
{
    public static bool IsSet

        
相关标签:
12条回答
  • 2020-11-22 15:55

    You can achieve this using IL Weaving and ExtraConstraints

    Allows you to write this code

    public class Sample
    {
        public void MethodWithDelegateConstraint<[DelegateConstraint] T> ()
        {        
        }
        public void MethodWithEnumConstraint<[EnumConstraint] T>()
        {
        }
    }
    

    What gets compiled

    public class Sample
    {
        public void MethodWithDelegateConstraint<T>() where T: Delegate
        {
        }
    
        public void MethodWithEnumConstraint<T>() where T: struct, Enum
        {
        }
    }
    
    0 讨论(0)
  • 2020-11-22 16:03

    The way I do it is put a struct constraint, then check that T is an enum at runtime. This doesn't eliminate the problem completely, but it does reduce it somewhat

    0 讨论(0)
  • 2020-11-22 16:06

    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...

    0 讨论(0)
  • 2020-11-22 16:08

    Darren, that would work if the types were specific enumerations - for general enumerations to work you have to cast them to ints (or more likely uint) to do the boolean math:

    public static bool IsSet( this Enum input, Enum matchTo )
    {
        return ( Convert.ToUInt32( input ) & Convert.ToUInt32( matchTo ) ) != 0;
    }
    
    0 讨论(0)
  • 2020-11-22 16:10

    This doesn't answer the original question, but there is now a method in .NET 4 called Enum.HasFlag which does what you are trying to do in your example

    0 讨论(0)
  • 2020-11-22 16:11

    I just wanted to add Enum as a generic constraint.

    While this is just for a tiny helper method using ExtraConstraints is a bit too much overhead for me.

    I decided to just just create a struct constraint and add a runtime check for IsEnum. For converting a variable from T to Enum I cast it to object first.

        public static Converter<T, string> CreateConverter<T>() where T : struct
        {
            if (!typeof(T).IsEnum) throw new ArgumentException("Given Type is not an Enum");
            return new Converter<T, string>(x => ((Enum)(object)x).GetEnumDescription());
        }
    
    0 讨论(0)
提交回复
热议问题