Est-il possible de définir une conversion implicite d'énumérations en c #?
quelque chose qui pourrait y parvenir?
public enum MyEnum
{
one = 1, two = 2
}
MyEnum number = MyEnum.one;
long i = number;
Sinon, pourquoi pas?
c#
enums
implicit-conversion
implicit
Adam Naylor
la source
la source
enum YesNo {Yes, No}
qui pourrait implicitement se convertir en bool.Réponses:
Il existe une solution. Considérer ce qui suit:
Ce qui précède offre une conversion implicite:
C'est un peu plus de travail que de déclarer une énumération normale (bien que vous puissiez refactoriser certains des éléments ci-dessus dans une classe de base générique commune). Vous pouvez aller encore plus loin en demandant à la classe de base d'implémenter IComparable & IEquatable, ainsi qu'en ajoutant des méthodes pour renvoyer la valeur de DescriptionAttributes, les noms déclarés, etc., etc.
J'ai écrit une classe de base (RichEnum <>) pour gérer la plupart des travaux difficiles, ce qui facilite la déclaration d'énumérations ci-dessus jusqu'à:
La classe de base (RichEnum) est répertoriée ci-dessous.
la source
Vous ne pouvez pas faire de conversions implicites (sauf zéro), et vous ne pouvez pas écrire vos propres méthodes d'instance - cependant, vous pouvez probablement écrire vos propres méthodes d'extension:
Cela ne vous donne pas beaucoup, cependant (par rapport à simplement faire un casting explicite).
L'une des principales fois où j'ai vu des gens le vouloir, c'est pour faire de la
[Flags]
manipulation via des génériques - c'est-à-dire unebool IsFlagSet<T>(T value, T flag);
méthode. Malheureusement, C # 3.0 ne prend pas en charge les opérateurs sur les génériques, mais vous pouvez contourner ce problème en utilisant des choses comme celle-ci , qui rendent les opérateurs entièrement disponibles avec les génériques.la source
la source
static class
je suppose. Il n'y a aucun avantage à défendre l'un ou l'autre cas dans leIL
code final .J'ai adapté l'excellente classe de base générique RichEnum de Mark.
Fixation
Félicitations à Mark pour la splendide idée + mise en œuvre, voici à vous tous:
Un exemple d'utilisation que j'ai exécuté en mono:
Produire la sortie
Remarque: mono 2.6.7 nécessite un cast explicite supplémentaire qui n'est pas nécessaire lors de l'utilisation de mono 2.8.2 ...
la source
FirstOrDefault
, pour éviter de supposer qu'il n'y a qu'un seul attribut). Que ce soit ou non assumer de telles choses est « une bonne idée » (ou une mauvaise personne, car cette question) est bien sûr, en fonction du contexteTDerived instance = (TDerived)field.GetValue(null);
résultats eninstance
êtrenull
. Il semble que le runtime Mono doit avoir un ordre d'initialisation de type différent de celui de .NET qui permet à cela de fonctionner. Déroutant! J'ai dû à la place déplacer ce code dans une méthode statique et l'appeler à partir de l'initialiseur de type dans la sous-classe.Vous ne pouvez pas déclarer de conversions implicites sur les types enum, car ils ne peuvent pas définir de méthodes. Le mot clé implicite C # se compile en une méthode commençant par 'op_', et cela ne fonctionnerait pas dans ce cas.
la source
Vous pourriez probablement, mais pas pour l'énumération (vous ne pouvez pas y ajouter de méthode). Vous pouvez ajouter une conversion implicite à votre propre classe pour permettre à une énumération d'y être convertie,
La question serait pourquoi?
En général .Net évite (et vous devriez aussi) toute conversion implicite où des données peuvent être perdues.
la source
Si vous définissez la base de l'énumération comme longue, vous pouvez effectuer une conversion explicite. Je ne sais pas si vous pouvez utiliser des conversions implicites car les énumérations ne peuvent pas avoir de méthodes définies sur elles.
De plus, sachez qu'une énumération non activée sera par défaut la valeur 0, ou le premier élément - donc dans la situation ci-dessus, il serait probablement préférable de définir
zero = 0
également.la source
: long
ici; la conversion explicite fonctionnerait bien sans elle. La seule conversion implicite légale est zéro.les énumérations me sont largement inutiles à cause de cela, OP.
Je finis par faire des photos tout le temps:
la solution simple
Un exemple de problème classique est le jeu VirtualKey pour détecter les pressions sur les touches.
problème ici est que vous ne pouvez pas indexer le tableau avec l'énumération car il ne peut pas convertir implicitement enum en ushort (même si nous avons même basé l'énumération sur ushort)
dans ce contexte spécifique, les énumérations sont obsolètes par la structure de données suivante. . . .
la source
J'ai contourné un problème avec la réponse de sehe lors de l'exécution du code sur MS .net (non Mono). Pour moi spécifiquement, le problème s'est produit sur .net 4.5.1 mais d'autres versions semblent également affectées.
Le problème
accéder à un
public static TDervied MyEnumValue
par réflexion (viaFieldInfo.GetValue(null)
n'initialise pas ledit champ.La solution de contournement
Au lieu d'attribuer des noms aux
TDerived
instances lors de l'initialisation statique,RichEnum<TValue, TDerived>
cela se fait paresseusement lors du premier accès deTDerived.Name
. Le code:qui - dans mon cas - est basé sur
EquatableBase<T>
:Remarque
Le code ci-dessus n'intègre pas toutes les fonctionnalités de la réponse originale de Mark !
Merci
Merci à Mark pour sa
RichEnum
mise en œuvre et merci à sehe d' avoir apporté quelques améliorations!la source
J'ai trouvé une solution encore plus simple tirée d'ici /codereview/7566/enum-vs-int-wrapper-struct J'ai collé le code ci-dessous à partir de ce lien juste au cas où cela ne fonctionnerait pas à l'avenir.
la source
J'ai créé cet utilitaire pour m'aider à convertir un Enum en PrimitiveEnum et PrimitiveEnum en
byte, sbyte, short, ushort, int, uint, long, or ulong
.Donc, cela convertit techniquement toute énumération en une valeur primitive.
Voir commit sur https://github.com/McKabue/McKabue.Extentions.Utility/blob/master/src/McKabue.Extentions.Utility/Enums/PrimitiveEnum.cs
la source
uint
s pour lesquelles le jeu lui-même fait généralement desenum
s, mais le framework n'en sait rien. Devoir le faire(uint)
lors de l'appel du framework était une douleur. Votre idée à l'envers fonctionne parfaitement. Au lieu destruct
stocker leEnum
, j'ai unstruct IdNumber
qui stocke leuint
mais convertit implicitement leEnum
s que le jeu utilise. Au lieu de taper les paramètres du framework commeuint
, je peux les taperIdNumber
, et le framework peut les transmettre en interne efficacement, même en faisant des opérations intégrales sur eux.L'introduction de conversions implicites pour les types enum briserait la sécurité des types, donc je ne recommanderais pas de le faire. Pourquoi voudriez-vous faire ça? Le seul cas d'utilisation pour cela que j'ai vu est lorsque vous souhaitez placer les valeurs d'énumération dans une structure avec une disposition prédéfinie. Mais même dans ce cas, vous pouvez utiliser le type enum dans la structure et simplement dire au Marshaller ce qu'il doit en faire.
la source