Я часто видел и использовал перечисления с прикрепленными атрибутами для выполнения некоторых основных действий, таких как предоставление отображаемого имени или description:
public enum Movement {
[DisplayName("Turned Right")]
TurnedRight,
[DisplayName("Turned Left")]
[Description("Execute 90 degree turn to the left")]
TurnedLeft,
// ...
}
И у вас есть набор методов расширения для поддержки атрибутов:
public static string GetDisplayName(this Movement movement) { ... }
public static Movement GetNextTurn(this Movement movement, ...) { ... }
Следуя этому шаблону, дополнительные существующие или настраиваемые атрибуты могут быть применены к полям для других целей. Это похоже на то, как если бы перечисление могло работать как простой тип перечисляемого значения, которым оно является, и как более богатый объект неизменяемого значения с рядом полей:
public class Movement
{
public int Value { get; set; } // i.e. the type backing the enum
public string DisplayName { get; set; }
public string Description { get; set; }
public Movement GetNextTurn(...) { ... }
// ...
}
Таким образом, оно может «перемещаться» как простое поле во время сериализации, Быстро сравнивать и т. д., но поведение можно «усвоить» (аля ООП).
Тем не менее, я понимаю, что это можно рассматривать как антипаттерн. В то же время часть меня считает это достаточно полезным, чтобы анти мог быть слишком строгим.