可以很好地处理枚举和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
,则重新编号它们,这可能会很烦人。
谢谢。
如果你问我,你不应该在你的枚举值中编码这些数据。最好在可以获得此信息的地方应用属性。让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
之间的依赖关系。