Я часто видел и использовал перечисления с прикрепленными атрибутами, чтобы сделать некоторые основные вещи, такие как предоставление отображаемого имени или описания:
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(...) { ... }
// ...
}
Таким образом, он может "путешествовать" как простое поле во время сериализации, быстро сравниваться и т.д., но поведение может быть "интернализировано" (ala OOP).
Тем не менее, я признаю, что это можно считать анти-шаблоном. В то же время часть меня считает это достаточно полезным, что анти может быть слишком строгим.