C #: есть ли способ классифицировать перечисления? - PullRequest
13 голосов
/ 21 января 2010

Дано следующее перечисление:

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

Можно ли классифицировать именованные константы так, чтобы я мог пометить «Защитник» и «Бегущий» в качестве наступательных позиций, а «Защитный конец» и «Полузащитник» в качестве защитных позиций?

Ответы [ 9 ]

21 голосов
/ 21 января 2010

Вы можете использовать атрибуты:

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

А затем проверьте IsDefined на соответствующем FieldInfo. Синтаксис не очень красив, но вы можете добавить несколько методов расширения, чтобы сделать вещи более управляемыми:

public static bool IsOffensivePosition(PositionType pt)
{
    return typeof(PositionType).GetField(Enum.GetName(typeof(PositionType), pt)).
        IsDefined(typeof(OffensivePositionAttribute), false);
}
7 голосов
/ 21 января 2010

Почему бы не поцеловать:

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;

        }
    }
}
7 голосов
/ 21 января 2010

Вы можете использовать атрибут, например CategoryAttribute:

public enum Position
{
    [Category("Offensive")]
    Quarterback,
    [Category("Offensive")]
    Runningback,
    [Category("Defensive")]
    DefensiveEnd,
    [Category("Defensive")]
    Linebacker
};
5 голосов
/ 21 января 2010
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
5 голосов
/ 21 января 2010

Вы можете использовать Флаги

[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);
    }
3 голосов
/ 21 января 2010

Может быть, вы можете попробовать использовать 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 };
}
1 голос
/ 21 января 2010

Недоиспользуемый (но вполне допустимый) метод заключается в использовании класса, который определяет набор констант. Как класс, вы можете добавить дополнительные свойства, которые могут описывать другие аспекты перечисляемого значения. Любопытно, что именно так большинство перечислений реализовано в Java (для них нет специального ключевого слова).

Если вы идете по этому пути, обычно рекомендуется сделать класс запечатанным и определить личный конструктор, чтобы только сам класс мог определять экземпляры. Вот пример:

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...
}

Использование такого перечисления приводит к более элегантному и простому синтаксису, чем атрибуты:

if( PlayerPosition.Quarterback.IsDefensive )
{
    // ...
}
0 голосов
/ 21 января 2010

Вы можете объявить перечисления в классе:

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

Обратите внимание, что защитные значения начинаются с 10, чтобы значения не перекрывались. Вы не указываете, почему вы хотите это сделать, поэтому это может не соответствовать вашим потребностям.

0 голосов
/ 21 января 2010

Вы можете использовать некоторую форму битов флага. Но это может привести к беспорядку. Лучшим способом может быть просто создать пользовательские классы с нужными вам деталями, а затем использовать словарь для поиска каждого типа позиции;

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; }
}

... как перечисление ...

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

    Defensive = 0x10,
    Offsensive = 0x20
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...