С#: Есть ли способ классифицировать перечисления?

Учитывая следующее перечисление:

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

Можно ли классифицировать именованные константы, чтобы я мог отмечать "Quarterback" и "Runningback" как оскорбительные позиции и "DefensiveEnd" и "Linebacker" в качестве оборонительных позиций?

Ответы

Ответ 1

Почему не KISS:

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

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

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

Ответ 3

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

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

Ответ 4

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

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

Ответ 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

Ответ 6

Возможно, вы можете попытаться использовать typeefe 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 };
}

Ответ 7

Недоиспользуемый (но совершенно правильный) метод заключается в использовании класса, который определяет набор констант. В качестве класса вы можете добавить дополнительные свойства, которые могут описывать другие аспекты перечисленного значения. Любопытно, что это то, как большинство перечислений реализовано на 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 )
{
    // ...
}

Ответ 8

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

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
}

Ответ 9

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

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

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