Enum as Generic Constraint: What's the reason Microsoft didn't want to implement it?
I understand that it enum
cannot be used as a general restriction and Microsoft declined to fix this bug .
For what reason?
a source to share
The link you provided says why:
and is a somewhat arbitrary language constraint
Potentially changes:
If we ever expose constraints as a function, it will be one of the things we will re-evaluate. For the upcoming release, we do not have the option to add additional language features, so you will see that this is resolved as "Do Not Fix", but it remains on our lists for further review.
a source to share
I suspect that the reason it is enum
not accepted as a generic limitation is that while there are some things that can be "expected" to be able to do with an enumerated constraint parameter that cannot be done with an unbounded parameter, the only which would actually work causes very slow non-generic HasFlag
; in particular, operations that involve converting between an enumeration and its associated base type will not be used. Providing a constraint that prevents programmers from using variables in the ways they would expect, but only adds the ability to call a terribly slow non-generic method would seem to be worthless.
Be that as it may, I don't think being able to use enum
as a type constraint would be a loss, but for adding a feature that was not expected when the decision was made: extension methods and their interaction with Intellisense. If you write a method bool FlagCheck.HasAnyFlags<T>(T enum1, T enum2) where T:struct
that takes two enumerations of the same type and checks to see if there are any flags that are also in the other [you can write such a method about an order of magnitude faster than Enum.HasFlag
], it might not make sense to call it type parametersdouble
but the only consequence of this is that things like this will be caught at runtime, not at compile time. This is only if you make an extension method such that the lack of an enum constraint becomes annoying; in this case, it means that there is no way to offer Intellisense HasAnyFlags
for a variable of type enum
without also calling variables of other types.
By the way, I disagree with the constraint philosophy enum
for the same reason that I disagree with the rule that you can't contain a closed type. Even if it would be useless to create a type parameter that is limited to a type that is always sealed, the fact that the type is sealed in the [possibly preview] version of the assembly implies that this will always be the case. Also, if the type is not unsealed, but only has constructors internal
[called by factory methods], I don't know that replacing it with a sealed class would be a change, but for the closed type constraints rule.
a source to share
The base type problems and performance are valid, but they have workarounds, and the CLR and C ++ / CLI support common enumeration constraints. Working with flag enums has always been less readable than I prefer. HasFlag helps, but as pointed out there is room for performance improvements.
I have this and several other useful / enper / enper enum methods here . If you really need to write a method that restricts the enum type, this language can handle it, and not all that hard to learn is enough to write if these simple methods come from a C # background.
I suspect that some of the limitations of the generic enumeration types I experienced in C ++ / CLI have something to do with reasons why it was considered "not important enough". For example, most of the useful operators are missing other than assignment. To do anything with TEnum you have to drop the base type, which can be expensive depending on how you do it. Consider a binary add / remove / test operation for a flag extremely fast, adding a conversion requirement of one type dramatically changes performance. Changing to a base type value in C ++ / CLI can be done very quickly in a way that is implemented in IL as the equivalent of "taking an enum parameter and passing it as if it were actually the base type."However, doing this back to enumeration is not possible in C ++ / CLI and requires a call to Enum.ToObject, which is an expensive conversion.
I've implemented a workaround that basically takes a bunch of "convertBackToTEnum" methods and rewrites the IL to do it exactly the way the ConvertToUnderlyingType methods do.
The throws are also risky if you mess up and apply the wrong base type. I was worried enough that I had written a T4 script to generate unit tests for each operation for each base type (with values that could cause problems if converted incorrectly).
If you need to write methods that support this, there are several examples in the above project, including class and method constraints.
a source to share