Хорошо работает со значениями Enums и HEX - PullRequest
1 голос
/ 21 сентября 2011

У меня есть список перечислений следующим образом:

public enum EventID : uint
{
    SAMPLE_EVENT_1 = 0xDCCA0000,
    SAMPLE_EVENT_2 = 0xDCCB0001,
    SAMPLE_EVENT_3 = 0xDCCA0002,
    SAMPLE_EVENT_4 = 0xDCC00003,
    SAMPLE_EVENT_5 = 0xDCCA0004,
    ...
}

Шестнадцатеричное значение для каждого перечисления расшифровывается следующим образом:

/// DCC X XXXX 
/// --- - ----
///  |  |  |--> Notification ID (0x0000 to 0xFFFF)
///  |  |-----> Notification Type (0x0 to 0xA)
///  |--------> Sub-system ID (0xDCC)

Каков наилучший способ присвоения значений enum, так что добавление enum позже не будет означать переназначение всех значений. Выбираются только идентификатор подсистемы и тип уведомления, идентификатор уведомления должен назначаться автоматически.

Например, это могло бы раздражать, если были тысячи enum, и мне пришлось бы нумеровать их вручную или перенумеровать, если добавить enum в середине.

Спасибо.

Ответы [ 4 ]

3 голосов
/ 21 сентября 2011

Если вы спросите меня, вам не следует кодировать эти данные в значениях перечисления.Было бы лучше применить атрибуты их, где вы могли бы получить эту информацию.Пусть фактическое значение перечисления представляет собой NotificationId для получения автоматически назначенных значений.

[AttributeUsage(AttributeTargets.Field, AllowMultiple=false)]
public class SubsystemIdAttribute : Attribute
{
    public SubsystemIdAttribute(ushort value)
    {
        this.Value = (ushort)(value & 0xFFF);
    }

    public ushort Value { get; private set; }
}

[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public class NotificationTypeAttribute : Attribute
{
    public NotificationTypeAttribute(byte value)
    {
        this.Value = (byte)(value & 0xF);
    }

    public byte Value { get; private set; }
}

public enum EventId
{
    [SubsystemId(0xDCC)] [NotificationType(0xA)] SAMPLE_EVENT_1,
    [SubsystemId(0xDCC)] [NotificationType(0xB)] SAMPLE_EVENT_2,
    [SubsystemId(0xDCC)] [NotificationType(0xA)] SAMPLE_EVENT_3,
    [SubsystemId(0xDCC)] [NotificationType(0x0)] SAMPLE_EVENT_4,
    [SubsystemId(0xDCC)] [NotificationType(0xA)] SAMPLE_EVENT_5,
}

public static class EventIdExtensions
{
    public static ushort GetSubsystemId(this EventId eventId)
    {
        return GetAttributeValue(eventId, (SubsystemIdAttribute a) => a.Value);
    }

    public static byte GetNotificationType(this EventId eventId)
    {
        return GetAttributeValue(eventId, (NotificationTypeAttribute a) => a.Value);
    }

    private static TValue GetAttributeValue<TAttribute, TValue>(EventId eventId, Func<TAttribute, TValue> selector)
        where TAttribute : Attribute
    {
        return typeof(EventId).GetField(eventId.ToString())
            .GetCustomAttributes(false)
            .OfType<TAttribute>()
            .Select(selector)
            .Single();
    }
}

Чтобы получить значения атрибутов, вызовите соответствующие методы расширения.

var eventId = EventId.SAMPLE_EVENT_3;
var subsystemId = eventId.GetSubsystemId();           // 0xDCC
var notificationType = eventId.GetNotificationType(); // 0xA
0 голосов
/ 21 сентября 2011

Если вы довольны ответом Джеффа это намного более чистый дизайн

public class EventId
{
    public static readonly SAMPLE_EVENT_1 = new EventId(0xDCC, 0xA);
    public static readonly SAMPLE_EVENT_2 = new EventId(0xDCC, 0xA);
    public static readonly SAMPLE_EVENT_3 = new EventId(0xDCC, 0xA);
    public static readonly SAMPLE_EVENT_4 = new EventId(0xDCC, 0xA);

    public readonly ushort SubSystemId;
    public readonly byte NotificationType;
    public readonly ushort NotificationId;

    private static ushort notificationCounter = 0;

    private EventId(ushort subSystemId, byte notificationType)
    {
        this.SubSystemId = subSystemId;
        this.NotificationType= notificationType;
        this.NotificationId = notificationCounter++;
    }
}

Но, конечно, вы создаете зависимость между компилятором и NotificationId, которая вам, вероятно, не нравится.

0 голосов
/ 21 сентября 2011

Полагаю, цель ваших перечислений - дать имена событиям с определенными кодами.Вопрос в том, что является каноническим источником ассоциации между именами и кодами.Если это вы (или ваш код), я не вижу причин для нумерации.Если это происходит из какого-то внешнего источника (например, документации), попробуйте развернуть генерацию кода (например, T4 шаблоны ).

0 голосов
/ 21 сентября 2011

Перечисляет только автоинкремент на 1, поэтому вам нужно будет хранить их в порядке по подсистеме, затем по типу уведомления, затем по идентификатору уведомления и только при наличии промежутков, которые вы можете назначить. Таким образом, чтобы сохранить порядок, вышеприведенное перечисление будет выглядеть так:

public enum EventID : uint
{
    SAMPLE_EVENT_1 = 0xDCCA0000,
    SAMPLE_EVENT_3 = 0xDCCA0002,
    SAMPLE_EVENT_5 = 0xDCCA0004,
    SAMPLE_EVENT_2 = 0xDCCB0001,
    SAMPLE_EVENT_4 = 0xDCC00003,
}
...