2010-01-21 5 views
13

Compte tenu de la ENUM suivante:C#: Existe-t-il un moyen de classer les énumérations?

public enum Position 
    { 
     Quarterback, 
     Runningback, 
     DefensiveEnd, 
     Linebacker 
    }; 

Est-il possible de classer les constantes nommées, de sorte que je pouvais marquer « Quarterback » et « Runningback » comme des positions offensives et « defensive end » et « Le secondeur » comme des positions défensives?

+0

Il est une question intéressante même si elle essaie énumérations d'abus, j'ai une question en retour ... pourquoi n'êtes-vous pas utiliser un lecteur de classe avec des propriétés pour la position et si elles sont sur l'équipe défensive ou offensive? – Lazarus

Répondre

7

Pourquoi ne pas BAISER:

class PlayerPosition { 
    public enum Position { 
     Quarterback, 
     Runningback, 
     DefensiveEnd, 
     Linebacker 
    } 

    public enum Type { 
     Offense, 
     Defense 
    } 


    public static Type GetTypeForPosition(Position position) { 
     switch (position) { 
      case Quarterback: 
      case Runningback: 
       return Type.Offense; 
      case DefensiveEnd: 
      case Linebacker: 
       return Type.Defense; 

     } 
    } 
} 
+2

Vous pourriez vouloir utiliser un nom d'énumération autre que Type, ayant System.Type autour et tout. Désambiguïser chaque fois que vous l'utilisez peut être vraiment ennuyeux. :) – GeReV

21

Vous pouvez utiliser des attributs:

public enum Position 
{ 
    [OffensivePosition] 
    Quarterback, 
    [OffensivePosition] 
    Runningback, 
    [DefensivePosition] 
    DefensiveEnd, 
    [DefensivePosition] 
    Linebacker 
}; 

Et puis vérifier IsDefined sur un FieldInfo approprié. La syntaxe est pas très jolie, mais vous pouvez jeter dans quelques méthodes d'extension pour rendre les choses plus manageble:

public static bool IsOffensivePosition(PositionType pt) 
{ 
    return typeof(PositionType).GetField(Enum.GetName(typeof(PositionType), pt)). 
     IsDefined(typeof(OffensivePositionAttribute), false); 
} 
+1

+1 J'ai utilisé cette méthode dans une situation similaire mais j'ai trouvé que l'obtention des attributs est assez pénible dans le cas d'énumérations –

+0

Ce n'est pas nécessairement douloureux ... vous pouvez créer une méthode d'extension pour récupérer l'attribut , et juste le réutiliser chaque fois que vous en avez besoin –

+0

Déjà donné mon +1, même si je trouve que la réflexion est parfois une méthode plutôt coûteuse pour une telle folie. =) –

5

Vous pouvez utiliser Flags

[Flags] 
public enum Position 
    { 
     Quarterback = 1, 
     Runningback = 2, 
     DefensiveEnd = 4, 
     Linebacker = 8, 

     OffensivePosition = Quarterback | Runningback, 
     DefensivePosition = Linebacker | DefensiveEnd, 

    }; 

    //strictly for example purposes 
    public bool isOffensive(Position pos) 
    { 
     return !((pos & OffensivePosition) == pos); 
    } 
+1

Souhaitez-vous nous expliquer comment les drapeaux pourraient résoudre la question des demandeurs? –

+2

Lorsque vous utilisez '[Flags]', vous devez également spécifier des constantes d'énumération en puissances de deux. – Thorarin

+0

Je suis d'accord que vous devriez mais vous n'avez pas explicitement besoin de le faire – cgreeno

6

Vous pouvez utiliser un attribut, comme CategoryAttribute:

public enum Position 
{ 
    [Category("Offensive")] 
    Quarterback, 
    [Category("Offensive")] 
    Runningback, 
    [Category("Defensive")] 
    DefensiveEnd, 
    [Category("Defensive")] 
    Linebacker 
}; 
+1

CategoryAttribute est destiné au regroupement de propriétés ou d'événements dans PropertyGrid et ne devrait probablement pas être abusé pour ce genre de chose. =) –

+1

Pourquoi pas? Il peut être appliqué à n'importe quoi, pas seulement aux propriétés ou aux événements. OK, peut-être que ce n'est pas * destiné * à cette utilisation, mais il exprime la signification souhaitée plutôt bien à mon avis ... –

+0

System.ComponentModel.CategoryAttribute a déjà un usage - pour moi, il donne une signification complètement différente de ce qui est prévu. –

0

Vous pouvez utiliser une forme de bits de drapeau. Mais cela pourrait conduire à un désordre. Une meilleure façon peut être de simplement créer des classes personnalisées avec les détails que vous voulez, puis utiliser un dictionnaire pour rechercher chaque type de position;

public class PlayerPosition { 
    public PlayerPosition (string positionName, bool isDefensive) { 
     this.Name = positionName; 
     this.IsDefensive = isDefensive ; 
    } 
    public string Name { get; private set; } 
    public bool IsDefensive { get; private set; } 
} 

... ENUM ...

[Flags] 
public enum Positions { 
    Quarterback = 0x21, 
    Runningback = 0x22, 
    DefensiveEnd = 0x14, 
    Linebacker = 0x18, 

    Defensive = 0x10, 
    Offsensive = 0x20 
} 
+0

doux ... bas vote sans commentaire. comment gentil ... –

3

Peut-être que vous pouvez essayer d'utiliser typesefe enum pattern

class Position 
{ 
    public bool Offensive { get; private set; } 
    public bool Defensive { get; private set; } 

    private Position() 
    { 
     Offensive = false; 
     Defensive = false; 
    } 

    public static readonly Position Quarterback = new Position() { Offensive = true }; 
    public static readonly Position Runningback = new Position() { Offensive = true }; 
    public static readonly Position DefensiveEnd = new Position() { Defensive = true }; 
    public static readonly Position Linebacker = new Position() { Defensive = true }; 
} 
+0

% s/private Possition/privé Position/g –

+0

@iferrorthrownewbrick: ty. terminé. –

1

Un sous-utilisé (mais parfaitement valide) technique est d'utiliser une classe qui définit un ensemble de constantes. En tant que classe, vous pouvez ajouter des propriétés supplémentaires pouvant décrire d'autres aspects de la valeur énumérée. Curieusement, c'est la façon dont la plupart des enums sont implémentés en Java (qui n'a pas de mot-clé spécial pour eux).

Si vous suivez cette route, c'est généralement une bonne idée de sceller la classe et de définir un constructeur privé, afin que seule la classe elle-même puisse définir des instances. Voici un exemple:

public static class Position 
{ 
    private PlayerPosition (string name, bool isDefensive) { 
     this.Name = name 
     this.IsDefensive = isDefensive ; 
    } 
    // any properties you may need... 
    public string Name { get; private set; } 
    public bool IsDefensive { get; private set; } 
    public bool IsOffensive { get { return !IsDefensive; } } 

    // static instances that act like an enum 
    public static readonly Quarterback = new PlayerPosition("Quarterback", false); 
    public static readonly Runningback = new PlayerPosition("Runningback", false); 
    public static readonly Linebacker = new PlayerPosition("Linebacker", true); 
    // etc... 
} 

En utilisant un tel résultat enum dans la syntaxe plus élégante et plus simple que les attributs:

if(PlayerPosition.Quarterback.IsDefensive) 
{ 
    // ... 
} 
0

Vous pouvez déclarer les énumérations dans une classe:

public class Position 
{ 
    public enum Offensive { Quarterback = 1, RunningBack } 
    public enum Defensive { DefensiveEnd = 10, LineBacker } 
} 

Notez que Les valeurs défensives commencent à 10 afin que les valeurs ne se chevauchent pas. Vous n'indiquez pas pourquoi vous voulez faire cela, donc cela pourrait ne pas répondre à vos besoins.

5
public enum PositionType 
{ 
    Offensive, 
    Defensive, 
} 

public class PositionTypeAttribute : Attribute 
{ 
    public PositionTypeAttribute(PositionType positionType) 
    { 
     PositionType = positionType; 
    } 
    public PositionType PositionType { get; private set; } 
} 

public enum Position 
{ 
    [PositionType(PositionType.Offensive)] 
    Quarterback, 
    [PositionType(PositionType.Offensive)] 
    Runningback, 
    [PositionType(PositionType.Defensive)] 
    DefensiveEnd, 
    [PositionType(PositionType.Defensive)] 
    Linebacker 
}; 

public static class PositionHelper 
{ 
    public static PositionType GetPositionType(this Position position) 
    { 
     var positionTypeAttr = (PositionTypeAttribute)typeof(Position).GetField(Enum.GetName(typeof(Position), position)) 
      .GetCustomAttributes(typeof(PositionTypeAttribute), false)[0]; 
     return positionTypeAttr.PositionType; 

    } 
} 


Position position1 = Position.Runningback; 
Console.WriteLine(position1.GetPositionType()); //print: Offensive 

Position position2 = Position.Linebacker; 
Console.WriteLine(position2.GetPositionType()); //print: Defensive 
+0

+1 La combinaison ultime de techniques. Une énumération fournit le paramètre à un attribut utilisé pour décorer les valeurs de membre d'une autre énumération. – AnthonyWJones

+0

Yep :) Et la méthode d'extension simplifie grandement l'utilisation. –

+0

Celui-ci aide beaucoup, merci! spécialement parce que votre code est propre et satisfait tous les cas où nous avons besoin de ce genre d'arrangement. –