C#:Есть ли способ классифицировать перечисления?
-
22-09-2019 - |
Вопрос
Учитывая следующее перечисление:
public enum Position
{
Quarterback,
Runningback,
DefensiveEnd,
Linebacker
};
Можно ли классифицировать названные константы таким образом, чтобы я мог пометить "Квотербек" и "Раннингбек" как наступательные позиции, а "Защитник" и "Полузащитник" - как оборонительные позиции?
Решение
Почему бы не ПОЦЕЛОВАТЬСЯ:
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;
}
}
}
Другие советы
Вы можете использовать атрибуты:
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);
}
Вы могли бы использовать атрибут, например CategoryAttribute
:
public enum Position
{
[Category("Offensive")]
Quarterback,
[Category("Offensive")]
Runningback,
[Category("Defensive")]
DefensiveEnd,
[Category("Defensive")]
Linebacker
};
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
Вы могли бы использовать Флаги
[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);
}
Может быть, вы можете попробовать использовать шаблон перечисления typesefe
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 };
}
Недостаточно используемый (но вполне допустимый) метод заключается в использовании класса, который определяет набор констант.Как класс, вы можете добавить дополнительные свойства, которые могут описывать другие аспекты перечисляемого значения.Любопытно, что именно так большинство перечислений реализованы в 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 )
{
// ...
}
Вы могли бы использовать некоторую форму битов флага.Но это может привести к беспорядку.Лучшим способом может быть просто создание пользовательских классов с нужными вам сведениями, а затем использование словаря для поиска каждого типа позиции;
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
}
Вы можете объявить перечисления в классе:
public class Position
{
public enum Offensive { Quarterback = 1, RunningBack }
public enum Defensive { DefensiveEnd = 10, LineBacker }
}
Обратите внимание, что защитные значения начинаются с 10, чтобы значения не перекрывались.Вы не указываете, почему вы хотите это сделать, так что это может не соответствовать вашим потребностям.