Question

I have a list of enums as follows:

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

The hex value for each enum is deciphered as follows:

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

What is the best way to assign values to the enum's, such that adding enum's later won't mean reassigning all the values. The only Sub-system ID, and Notification Type are chosen, the Notification ID should be automatically assigned.

For example, it might get annoying if there were thousands of enum's and I had to number them by hand or renumber them if adding an enum in the middle.

Thanks.

Was it helpful?

Solution

If you asked me, you shouldn't be encoding this data in your enum values. It would be better to apply attributes the them instead where you could get this information. Let the actual value of the enum represent the NotificationId to get the automatically assigned values.

[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();
    }
}

To get the values of the attributes, call the appropriate extension methods.

var eventId = EventId.SAMPLE_EVENT_3;
var subsystemId = eventId.GetSubsystemId();           // 0xDCC
var notificationType = eventId.GetNotificationType(); // 0xA

OTHER TIPS

Enums only auto-increment by 1, so you'd have to keep them in order by sub-system, then notification type, then notification id, and only when there are gaps would you assign. So to keep order proper, your above enum would look like this:

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

I guess that purpose of your enums is to give a names to the events with specific codes. The question is what is the canonical source of association between names and codes. If it is you (or your code) I don't see any reason to renumber. If it comes from some external source (e.g. documentation) try to deploy some code generation (e.g. T4 templates).

If you are happy with Jeff's answer this is imho much more cleaner design

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++;
    }
}

But of course you creating dependency between compiler and NotificationId which you probably don't like.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top