Is there a workaround for generic type constraint of “special class” Enum in C# 3.0?

EDIT: A library is now available supporting this via ildasm/ilasm: UnconstrainedMelody Members of the C# team have previously said they'd like to be able to support where T : Enum and where T : Delegate but that it's never been a high enough priority. (I'm not sure what the reasoning is for having the restriction in the first place, admittedly...) The most practical workaround in C# is: public static bool HasFlags(this T value, T flags) where T : struct { if (!(value is Enum)) { throw new ArgumentException(); } // ... } That loses compile-time checking for the "enum-ness" but keeps the check that you're using the same type in both places. It has the execution-time penalty of the check as well, of course.

You can avoid that execution-time penalty after the first call by using a generic nested type for the implementation which throws the exception in a static constructor: public static bool HasFlags(this T value, T flags) where T : struct { if (!(value is Enum)) { throw new ArgumentException(); } return EnumHelper. HasFlags(value, flags); } private class EnumHelper where T : struct { static EnumHelper() { if (!typeof(Enum). IsAssignableFrom(typeof(T)) { throw new InvalidOperationException(); // Or something similar } } internal static HasFlags(T value, T flags) { ... } } As Greco mentions, you could write the method in C++/CLI and then reference the class library from C# as another option.

EDIT: A library is now available supporting this via ildasm/ilasm: UnconstrainedMelody. Members of the C# team have previously said they'd like to be able to support where T : Enum and where T : Delegate, but that it's never been a high enough priority. (I'm not sure what the reasoning is for having the restriction in the first place, admittedly...) The most practical workaround in C# is: public static bool HasFlags(this T value, T flags) where T : struct { if (!(value is Enum)) { throw new ArgumentException(); } // ... } That loses compile-time checking for the "enum-ness" but keeps the check that you're using the same type in both places.It has the execution-time penalty of the check as well, of course.

You can avoid that execution-time penalty after the first call by using a generic nested type for the implementation which throws the exception in a static constructor: public static bool HasFlags(this T value, T flags) where T : struct { if (!(value is Enum)) { throw new ArgumentException(); } return EnumHelper. HasFlags(value, flags); } private class EnumHelper where T : struct { static EnumHelper() { if (!typeof(Enum). IsAssignableFrom(typeof(T)) { throw new InvalidOperationException(); // Or something similar } } internal static HasFlags(T value, T flags) { ... } } As Greco mentions, you could write the method in C++/CLI and then reference the class library from C# as another option.

I think it's important to keep extension methods limited in scope and therefore I will not be using where T : struct due to the reasons mentioned in my question (123. HasFlags(456) would compile fine. ) I do like Greco's solution, but I can't justify creating a whole library for one method.Is it possible to set up a process to "inject" the C++/CLI into a C# library when compiling?

– Blixt Sep 10 '09 at 8:44 @Blixt: Well, you could look into binary rewriting, but it's probably going to be ugly. I wonder whether there'd be interest in an open source project for a bunch of "useful things one can do with delegates and enums"... – Jon Skeet Sep 10 '09 at 8:54 Okay, I would only do it if there was an "easy" way to do it =) And yes, judging from the discussions I've found on Google, this problem isn't all that rare, and I would definitely appreciate such a library. – Blixt Sep 10 '09 at 8:57 1 Blog post around the library idea... msmvps.

Com/blogs/jon_skeet/archive/2009/09/10/… – Jon Skeet Sep 10 '09 at 20:10 1 You could use ILMerge (research.microsoft. Com/en-us/people/mbarnett/ilmerge. Aspx) to include what would be a fairly vestigial C++/CLI assemly into your main code.

– Steve Gilham 09/09/108 at 7:10.

While the workaround works, it's not "in C# 3.0". – Lasse V. Karlsen?

Sep 10 '09 at 8:39 Hmm... Since it's only one extension method I wouldn't want to create a new C++ project for it. I doubt it is possible to set up the environment to compile C++/CLI into a C# library? – Blixt Sep 10 '09 at 8:41 That's a nice work-around.

I am wondering why this is not wiedly known after more than 4 years... – Daniel Brückner Sep 10 '09 at 9:31 I implemented the workaround and it works perfectly! Sadly I don't see myself using it unless I make the whole utility library into C++ code... Anyways, see my answer to this question for the code. – Blixt Sep 10 '09 at 10:26.

I couldn't resist having a go at the C++ work-around, and since I got it to work I figured I'd share it with the rest of ya! Here's the C++ code (my C++ is very rusty so please point out any errors, in particular how the arguments are defined): #include "stdafx. H" using namespace System; using namespace System::Runtime::CompilerServices; namespace Blixt { namespace Utilities { Extension public ref class EnumUtility abstract sealed { public: generic where T : value class, Enum Extension static bool HasFlags(T value, T flags) { __int64 mask = Convert::ToInt64(flags); return (Convert::ToInt64(value) & mask) == mask; } }; } } And the C# code for testing (console application): using System; using Blixt.

Utilities; namespace Blixt. Playground { Flags public enum Colors : byte { Black = 0, Red = 1, Green = 2, Blue = 4 } Flags public enum Tastes : byte { Nothing = 0, Sour = 1, Sweet = 2, Bitter = 4, Salty = 8 } class Program { static void Main(string args) { Colors c = Colors. Blue | Colors.

Red; Console. WriteLine("Green and blue? {0}", c.

HasFlags(Colors. Green | Colors. Red)); Console.

WriteLine("Blue? {0}", c. HasFlags(Colors.

Blue)); Console. WriteLine("Green? {0}", c.

HasFlags(Colors. Green)); Console. WriteLine("Red and blue?

{0}", c. HasFlags(Colors. Red | Colors.

Blue)); // Compilation error: //Console. WriteLine("Sour? {0}", c.

HasFlags(Tastes. Sour)); Console. WriteLine("Press any key to exit..."); Console.

ReadKey(true); } } }.

Actually, it is possible, with an ugly trick. However, it cannot be used for extension methods. Public abstract class Enums where Temp : class { public static TEnum Parse(string name) where TEnum : struct, Temp { return (TEnum)Enum.

Parse(typeof(TEnum), name); } } public abstract class Enums : Enums { } Enums. Parse("Local") If you want to, you can give Enums a private constructor and a public nested abstract inherited class with Temp as Enum, to prevent inherited versions for non-enums.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions