可以很好地处理枚举和HEX值

本文关键字:HEX 枚举 处理 很好 | 更新日期: 2023-09-27 18:09:25

我有一个枚举列表如下:

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

每个enum的十六进制值按如下方式解码:

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

enum赋值的最好方法是什么,这样以后添加enum就不会意味着重新分配所有的值。如果只选择子系统ID和通知类型,则应该自动分配通知ID。

例如,如果有数千个enum,我必须手工编号它们,或者如果在中间添加enum,则重新编号它们,这可能会很烦人。

谢谢。

可以很好地处理枚举和HEX值

如果你问我,你不应该在你的枚举值中编码这些数据。最好在可以获得此信息的地方应用属性。让enum的实际值代表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

枚举只能自动递增1,因此您必须按子系统,然后通知类型,然后通知id排序,并且只有在存在间隙时才会分配。因此,为了保持正确的顺序,上面的enum看起来像这样:

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

我猜您枚举的目的是为具有特定代码的事件提供名称。问题是名称和代码之间的关联的规范来源是什么。如果是你(或你的代码),我不认为有任何理由重新编号。如果它来自一些外部源(例如文档),尝试部署一些代码生成(例如T4模板)。

如果你对Jeff的回答感到满意,这是一个更简洁的设计

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之间的依赖关系。