Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. Other Discussions
  3. The Weird and The Wonderful
  4. Fun with Generic Enum Constraint

Fun with Generic Enum Constraint

Scheduled Pinned Locked Moved The Weird and The Wonderful
helpregexquestionannouncementlearning
11 Posts 8 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • B Offline
    B Offline
    Bernhard Hiller
    wrote on last edited by
    #1

    Ever tried to create a generic class which accepts Enum types only? Can be fun! I have a non-generic class EnumDescConverter and wanted to add a generic version EnumDescConverter<T>. Easy, isn't it? Just write

    public class EnumDescConverter<T> : EnumDescConverter where T : Enum

    and the error is

    Constraint cannot be special class 'System.Enum'

    Well, you have to use a different approach. An Enum is a struct which implements IConvertible. Hence you can do

    public class EnumDescConverter : EnumDescConverter where T : struct, IConvertible

    and then check in the constructor that T is really an enum: if (!enumType.IsEnum) { throw ...} And now let's do more bad things. ;P The non-generic class has a function

    public Enum GetEnumValue(string description)

    Let's add a generic version in the generic class so that we do not need to cast the return value to the type of the enum in use:

    public T GetEnumValue(string description)

    And the warning is:

    warning CS0108: 'EnumDescConverter.GetEnumValue(string)' hides inherited member 'EnumDescConverter.GetEnumValue(string)'. Use the new keyword if hiding was intended.

    A possible solution, but not nice. If you make the method in the base class virtual, and override it in the generic class, the error is:

    'EnumDescConverter.GetEnumValue(string)': return type must be 'System.Enum' to match overridden member 'EnumDescConverter.GetEnumValue(string)'

    Hm. Let me change the name of the function, and in its body just call the base class' method and cast the return value (not a nice solution either):

    public T GetEnumValueT(string description)
    {
    return (T)GetEnumValue(description);
    }

    And the next error arises:

    Cannot convert type 'System.Enum' to 'T'

    Of course,

    return GetEnumValue(description) as T;

    doesn't work either because an Enum is not a class:

    The type parameter 'T' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint

    But the problem can be solved by a double-cast:

    return (T)((object)GetEnumValue(description));

    That's Weird and Wonderful, isn't it? :-D

    D A B P J 5 Replies Last reply
    0
    • B Bernhard Hiller

      Ever tried to create a generic class which accepts Enum types only? Can be fun! I have a non-generic class EnumDescConverter and wanted to add a generic version EnumDescConverter<T>. Easy, isn't it? Just write

      public class EnumDescConverter<T> : EnumDescConverter where T : Enum

      and the error is

      Constraint cannot be special class 'System.Enum'

      Well, you have to use a different approach. An Enum is a struct which implements IConvertible. Hence you can do

      public class EnumDescConverter : EnumDescConverter where T : struct, IConvertible

      and then check in the constructor that T is really an enum: if (!enumType.IsEnum) { throw ...} And now let's do more bad things. ;P The non-generic class has a function

      public Enum GetEnumValue(string description)

      Let's add a generic version in the generic class so that we do not need to cast the return value to the type of the enum in use:

      public T GetEnumValue(string description)

      And the warning is:

      warning CS0108: 'EnumDescConverter.GetEnumValue(string)' hides inherited member 'EnumDescConverter.GetEnumValue(string)'. Use the new keyword if hiding was intended.

      A possible solution, but not nice. If you make the method in the base class virtual, and override it in the generic class, the error is:

      'EnumDescConverter.GetEnumValue(string)': return type must be 'System.Enum' to match overridden member 'EnumDescConverter.GetEnumValue(string)'

      Hm. Let me change the name of the function, and in its body just call the base class' method and cast the return value (not a nice solution either):

      public T GetEnumValueT(string description)
      {
      return (T)GetEnumValue(description);
      }

      And the next error arises:

      Cannot convert type 'System.Enum' to 'T'

      Of course,

      return GetEnumValue(description) as T;

      doesn't work either because an Enum is not a class:

      The type parameter 'T' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint

      But the problem can be solved by a double-cast:

      return (T)((object)GetEnumValue(description));

      That's Weird and Wonderful, isn't it? :-D

      D Offline
      D Offline
      Daniel Pfeffer
      wrote on last edited by
      #2

      :omg: X|

      If you have an important point to make, don't try to be subtle or clever. Use a pile driver. Hit the point once. Then come back and hit it again. Then hit it a third time - a tremendous whack. --Winston Churchill

      1 Reply Last reply
      0
      • B Bernhard Hiller

        Ever tried to create a generic class which accepts Enum types only? Can be fun! I have a non-generic class EnumDescConverter and wanted to add a generic version EnumDescConverter<T>. Easy, isn't it? Just write

        public class EnumDescConverter<T> : EnumDescConverter where T : Enum

        and the error is

        Constraint cannot be special class 'System.Enum'

        Well, you have to use a different approach. An Enum is a struct which implements IConvertible. Hence you can do

        public class EnumDescConverter : EnumDescConverter where T : struct, IConvertible

        and then check in the constructor that T is really an enum: if (!enumType.IsEnum) { throw ...} And now let's do more bad things. ;P The non-generic class has a function

        public Enum GetEnumValue(string description)

        Let's add a generic version in the generic class so that we do not need to cast the return value to the type of the enum in use:

        public T GetEnumValue(string description)

        And the warning is:

        warning CS0108: 'EnumDescConverter.GetEnumValue(string)' hides inherited member 'EnumDescConverter.GetEnumValue(string)'. Use the new keyword if hiding was intended.

        A possible solution, but not nice. If you make the method in the base class virtual, and override it in the generic class, the error is:

        'EnumDescConverter.GetEnumValue(string)': return type must be 'System.Enum' to match overridden member 'EnumDescConverter.GetEnumValue(string)'

        Hm. Let me change the name of the function, and in its body just call the base class' method and cast the return value (not a nice solution either):

        public T GetEnumValueT(string description)
        {
        return (T)GetEnumValue(description);
        }

        And the next error arises:

        Cannot convert type 'System.Enum' to 'T'

        Of course,

        return GetEnumValue(description) as T;

        doesn't work either because an Enum is not a class:

        The type parameter 'T' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint

        But the problem can be solved by a double-cast:

        return (T)((object)GetEnumValue(description));

        That's Weird and Wonderful, isn't it? :-D

        A Offline
        A Offline
        Agent__007
        wrote on last edited by
        #3

        A joke, I know, but that's just crazy! :laugh: :thumbsup:

        You have just been Sharapova'd.

        1 Reply Last reply
        0
        • B Bernhard Hiller

          Ever tried to create a generic class which accepts Enum types only? Can be fun! I have a non-generic class EnumDescConverter and wanted to add a generic version EnumDescConverter<T>. Easy, isn't it? Just write

          public class EnumDescConverter<T> : EnumDescConverter where T : Enum

          and the error is

          Constraint cannot be special class 'System.Enum'

          Well, you have to use a different approach. An Enum is a struct which implements IConvertible. Hence you can do

          public class EnumDescConverter : EnumDescConverter where T : struct, IConvertible

          and then check in the constructor that T is really an enum: if (!enumType.IsEnum) { throw ...} And now let's do more bad things. ;P The non-generic class has a function

          public Enum GetEnumValue(string description)

          Let's add a generic version in the generic class so that we do not need to cast the return value to the type of the enum in use:

          public T GetEnumValue(string description)

          And the warning is:

          warning CS0108: 'EnumDescConverter.GetEnumValue(string)' hides inherited member 'EnumDescConverter.GetEnumValue(string)'. Use the new keyword if hiding was intended.

          A possible solution, but not nice. If you make the method in the base class virtual, and override it in the generic class, the error is:

          'EnumDescConverter.GetEnumValue(string)': return type must be 'System.Enum' to match overridden member 'EnumDescConverter.GetEnumValue(string)'

          Hm. Let me change the name of the function, and in its body just call the base class' method and cast the return value (not a nice solution either):

          public T GetEnumValueT(string description)
          {
          return (T)GetEnumValue(description);
          }

          And the next error arises:

          Cannot convert type 'System.Enum' to 'T'

          Of course,

          return GetEnumValue(description) as T;

          doesn't work either because an Enum is not a class:

          The type parameter 'T' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint

          But the problem can be solved by a double-cast:

          return (T)((object)GetEnumValue(description));

          That's Weird and Wonderful, isn't it? :-D

          B Offline
          B Offline
          Brisingr Aerowing
          wrote on last edited by
          #4

          Fody can do that[^] The fact that you need a third party IL manipulation library to do this is still a WTF though. Edit: damn autoincorrect.

          What do you get when you cross a joke with a rhetorical question? The metaphorical solid rear-end expulsions have impacted the metaphorical motorized bladed rotating air movement mechanism. Do questions with multiple question marks annoy you???

          B 1 Reply Last reply
          0
          • B Brisingr Aerowing

            Fody can do that[^] The fact that you need a third party IL manipulation library to do this is still a WTF though. Edit: damn autoincorrect.

            What do you get when you cross a joke with a rhetorical question? The metaphorical solid rear-end expulsions have impacted the metaphorical motorized bladed rotating air movement mechanism. Do questions with multiple question marks annoy you???

            B Offline
            B Offline
            Bernhard Hiller
            wrote on last edited by
            #5

            Good find. Thanks.

            B 1 Reply Last reply
            0
            • B Bernhard Hiller

              Good find. Thanks.

              B Offline
              B Offline
              Brisingr Aerowing
              wrote on last edited by
              #6

              Fody is very powerful. I don't use it, but I have a few places that it might be of help.

              What do you get when you cross a joke with a rhetorical question? The metaphorical solid rear-end expulsions have impacted the metaphorical motorized bladed rotating air movement mechanism. Do questions with multiple question marks annoy you???

              1 Reply Last reply
              0
              • B Bernhard Hiller

                Ever tried to create a generic class which accepts Enum types only? Can be fun! I have a non-generic class EnumDescConverter and wanted to add a generic version EnumDescConverter<T>. Easy, isn't it? Just write

                public class EnumDescConverter<T> : EnumDescConverter where T : Enum

                and the error is

                Constraint cannot be special class 'System.Enum'

                Well, you have to use a different approach. An Enum is a struct which implements IConvertible. Hence you can do

                public class EnumDescConverter : EnumDescConverter where T : struct, IConvertible

                and then check in the constructor that T is really an enum: if (!enumType.IsEnum) { throw ...} And now let's do more bad things. ;P The non-generic class has a function

                public Enum GetEnumValue(string description)

                Let's add a generic version in the generic class so that we do not need to cast the return value to the type of the enum in use:

                public T GetEnumValue(string description)

                And the warning is:

                warning CS0108: 'EnumDescConverter.GetEnumValue(string)' hides inherited member 'EnumDescConverter.GetEnumValue(string)'. Use the new keyword if hiding was intended.

                A possible solution, but not nice. If you make the method in the base class virtual, and override it in the generic class, the error is:

                'EnumDescConverter.GetEnumValue(string)': return type must be 'System.Enum' to match overridden member 'EnumDescConverter.GetEnumValue(string)'

                Hm. Let me change the name of the function, and in its body just call the base class' method and cast the return value (not a nice solution either):

                public T GetEnumValueT(string description)
                {
                return (T)GetEnumValue(description);
                }

                And the next error arises:

                Cannot convert type 'System.Enum' to 'T'

                Of course,

                return GetEnumValue(description) as T;

                doesn't work either because an Enum is not a class:

                The type parameter 'T' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint

                But the problem can be solved by a double-cast:

                return (T)((object)GetEnumValue(description));

                That's Weird and Wonderful, isn't it? :-D

                P Offline
                P Offline
                PIEBALDconsult
                wrote on last edited by
                #7

                But have you tried doing math with enum values in a generic class? :sigh: EnumOperators[^] Generic Math in C# Using Runtime Compilation[^]

                Richard DeemingR 1 Reply Last reply
                0
                • P PIEBALDconsult

                  But have you tried doing math with enum values in a generic class? :sigh: EnumOperators[^] Generic Math in C# Using Runtime Compilation[^]

                  Richard DeemingR Offline
                  Richard DeemingR Offline
                  Richard Deeming
                  wrote on last edited by
                  #8

                  Apart from combining / testing Flags values, when does it ever make sense to perform mathematical operations on Enum values?


                  "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

                  "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

                  P 1 Reply Last reply
                  0
                  • Richard DeemingR Richard Deeming

                    Apart from combining / testing Flags values, when does it ever make sense to perform mathematical operations on Enum values?


                    "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

                    P Offline
                    P Offline
                    PIEBALDconsult
                    wrote on last edited by
                    #9

                    Just wait until you need to.

                    G 1 Reply Last reply
                    0
                    • P PIEBALDconsult

                      Just wait until you need to.

                      G Offline
                      G Offline
                      greldak
                      wrote on last edited by
                      #10

                      If you ever need to then the much higher priority should be to refactor that bit of code so that you use something more appropriate. The actual value applied to an enumeration should never be relied upon to remain the same between versions of the code and so the result of any maths operation performed on it should be considered unreliable.

                      1 Reply Last reply
                      0
                      • B Bernhard Hiller

                        Ever tried to create a generic class which accepts Enum types only? Can be fun! I have a non-generic class EnumDescConverter and wanted to add a generic version EnumDescConverter<T>. Easy, isn't it? Just write

                        public class EnumDescConverter<T> : EnumDescConverter where T : Enum

                        and the error is

                        Constraint cannot be special class 'System.Enum'

                        Well, you have to use a different approach. An Enum is a struct which implements IConvertible. Hence you can do

                        public class EnumDescConverter : EnumDescConverter where T : struct, IConvertible

                        and then check in the constructor that T is really an enum: if (!enumType.IsEnum) { throw ...} And now let's do more bad things. ;P The non-generic class has a function

                        public Enum GetEnumValue(string description)

                        Let's add a generic version in the generic class so that we do not need to cast the return value to the type of the enum in use:

                        public T GetEnumValue(string description)

                        And the warning is:

                        warning CS0108: 'EnumDescConverter.GetEnumValue(string)' hides inherited member 'EnumDescConverter.GetEnumValue(string)'. Use the new keyword if hiding was intended.

                        A possible solution, but not nice. If you make the method in the base class virtual, and override it in the generic class, the error is:

                        'EnumDescConverter.GetEnumValue(string)': return type must be 'System.Enum' to match overridden member 'EnumDescConverter.GetEnumValue(string)'

                        Hm. Let me change the name of the function, and in its body just call the base class' method and cast the return value (not a nice solution either):

                        public T GetEnumValueT(string description)
                        {
                        return (T)GetEnumValue(description);
                        }

                        And the next error arises:

                        Cannot convert type 'System.Enum' to 'T'

                        Of course,

                        return GetEnumValue(description) as T;

                        doesn't work either because an Enum is not a class:

                        The type parameter 'T' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint

                        But the problem can be solved by a double-cast:

                        return (T)((object)GetEnumValue(description));

                        That's Weird and Wonderful, isn't it? :-D

                        J Offline
                        J Offline
                        James Curran
                        wrote on last edited by
                        #11

                        In your last method, beside being awkward, you are boxing & unboxing the value. Which probably increase the time that method takes to run by at least one order of magnitude. A way to avoid this is to take advantage of something we already know... enums are `IConvertible`. void Main() { var b = new EnumDescConverter(); b.GetEnumValueT("Dummy desc").Dump(); } enum nums {zero, one, two, three}; enum Nums {Zero, One, Two, Three}; class EnumDescConverter { /// Simplified a bit for example. protected IConvertible GetEnumValue(string description) {return nums.one; } } class EnumDescConverter : EnumDescConverter where T : struct, IConvertible { public T GetEnumValueT(string description) { return (T) GetEnumValue(description);} } P.S. http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2557231-enums-constraint-for-generics[^]

                        Truth, James

                        1 Reply Last reply
                        0
                        Reply
                        • Reply as topic
                        Log in to reply
                        • Oldest to Newest
                        • Newest to Oldest
                        • Most Votes


                        • Login

                        • Don't have an account? Register

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • World
                        • Users
                        • Groups