Contraintes de type Enum en C #

Duplication possible:
Quelqu’un connaît-il une solution palliative à l’absence de contrainte générique?

Quelle est la raison derrière C # ne pas autoriser les contraintes de type sur Enum ? Je suis sûr qu’il y a une méthode derrière la folie, mais j’aimerais comprendre pourquoi ce n’est pas possible.

Voici ce que je voudrais pouvoir faire (en théorie).

 public static T GetEnum(this ssortingng description) where T : Enum { ... } 

Ceci est une fonctionnalité parfois demandée.

Comme je tiens à le souligner, TOUTES les fonctionnalités ne sont mises en œuvre que lorsque quelqu’un conçoit, spécifie, implémente, teste, documente et expédie la fonctionnalité. Jusqu’à présent, personne ne l’a fait pour celui-ci. Il n’y a pas de raison particulière pour cela. nous avons beaucoup d’autres choses à faire, des budgets limités, et celui-ci n’a jamais dépassé le «ça ne serait pas sympa? discussion dans l’équipe de conception linguistique.

Le CLR ne le prend pas en charge, donc pour que cela fonctionne, nous devons faire un travail d’exécution en plus du travail linguistique. (voir les commentaires de réponse)

Je peux voir qu’il y a quelques cas d’utilisation décents, mais aucun n’est tellement convaincant que nous ferions ce travail plutôt que l’une des centaines d’autres fonctionnalités beaucoup plus fréquemment demandées ou plus attrayantes et plus étendues. cas d’utilisation (Si nous allons en finir avec ce code, je privilégierais personnellement les contraintes des delegates, bien au-dessus des contraintes d’énumération.)

En fait, c’est possible, avec un truc moche. Cependant, il ne peut pas être utilisé pour les méthodes d’extension.

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

Si vous le souhaitez, vous pouvez atsortingbuer à Enums un constructeur privé et une classe abstraite publique nestede avec Temp as Enum , pour empêcher les versions héritées pour les non-enums.

Notez que vous ne pouvez pas utiliser cette astuce pour créer des méthodes d’extension.

 public static T GetEnum(this ssortingng description) where T : struct { return (T)Enum.Parse(typeof(T), description); } 

Répond-il à votre question?

Tissage IL en utilisant des contraintes supplémentaires

Votre code

 public static T GetEnum<[EnumConstraint] T>(this ssortingng description) { ... } 

Ce qui est compilé

 public static T GetEnum(this ssortingng description) where T : Enum { ... } 

Voici une version VB.NET de SLaks excellente , avec Imports tant que “typedef”: (L’inférence de type fonctionne comme prévu, mais vous ne pouvez pas obtenir de méthodes d’extension.)

 'Base namespace "EnumConstraint" Imports Enums = EnumConstraint.Enums(Of System.Enum) Public NotInheritable Class Enums(Of Temp As Class) Private Sub New() End Sub Public Shared Function Parse(Of TEnum As {Temp, Structure})(ByVal Name As Ssortingng) As TEnum Return DirectCast([Enum].Parse(GetType(TEnum), Name), TEnum) End Function Public Shared Function IsDefined(Of TEnum As {Temp, Structure})(ByVal Value As TEnum) As Boolean Return [Enum].IsDefined(GetType(TEnum), Value) End Function Public Shared Function HasFlags(Of TEnum As {Temp, Structure})(ByVal Value As TEnum, ByVal Flags As TEnum) As Boolean Dim flags64 As Long = Convert.ToInt64(Flags) Return (Convert.ToInt64(Value) And flags64) = flags64 End Function End Class Module Module1 Sub Main() Dim k = Enums.Parse(Of DateTimeKind)("Local") Console.WriteLine("{0} = {1}", k, CInt(k)) Console.WriteLine("IsDefined({0}) = {1}", k, Enums.IsDefined(k)) k = DirectCast(k * 2, DateTimeKind) Console.WriteLine("IsDefined({0}) = {1}", k, Enums.IsDefined(k)) Console.WriteLine(" {0} same as {1} Or {2}: {3} ", IO.FileAccess.ReadWrite, IO.FileAccess.Read, IO.FileAccess.Write, _ Enums.HasFlags(IO.FileAccess.ReadWrite, IO.FileAccess.Read Or IO.FileAccess.Write)) ' These fail to comstack as expected: 'Console.WriteLine(Enums.HasFlags(IO.FileAccess.ReadWrite, IO.FileOptions.RandomAccess)) 'Console.WriteLine(Enums.HasFlags(Of IO.FileAccess)(IO.FileAccess.ReadWrite, IO.FileOptions.RandomAccess)) If Debugger.IsAttached Then _ Console.ReadLine() End Sub End Module 

Sortie:

 Local = 2 IsDefined(Local) = True IsDefined(4) = False ReadWrite same as Read Or Write: True 

Une chose étrange est qu’il y a un bon nombre de méthodes Enum génériques que vous pouvez écrire, dont l’implémentation dépend du type “base” de l’énumération.

Par le type “base” d’une énumération, E , j’entends le type dans l’espace de noms System dont le nom est identique au nom du membre de l’énumération System.TypeCode obtenu en appelant System.Type.GetTypeCode(System.Type) pour le type E Si l’énumération a été déclarée en C #, c’est le même type que celui pour lequel elle a été déclarée “héritée” (je ne suis pas sûr de ce que cela est officiellement appelé dans la spécification). Par exemple, le type de base de l’énumération Animal ci-dessous est System.Byte :

 public enum Animal : byte { Moose, Squirrel } 

Il est possible d’écrire de telles méthodes à l’aide d’instructions switch, mais c’est certainement moche, vous ne pouvez pas obtenir des parameters fortement typés ou des types de retour dont le type est le type de base de l’énumération. (par exemple dans le constructeur statique du type générique contenant la méthode).