Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# alternative to enums for a n:m-relation

Tags:

c#

enums

casting

there are several threads on value-ranges in enums (not possible). But I have the following problem and search the best solution, where none of the provided once really satisfied me.

A specification of a protocol says that byte[x] of a message, the messagetype, has the following possible values (fantasy values):

0x00 = get
0x01 = set 
0x02 to 0xFF = identify

So there are only 3 different logical options, which would best be dealt with in an enum. But one of the n logical options has m different numerical counterparts, which is impossible to be dealt with in an enum.

Now what is the best (cleanest) solution for such a problem? I could build a class

class MessageType {
    public enum MessageTypeEnum {
        get = 0x00, 
        set = 0x01, 
        identify = 0x02
    }

    public static MessageTypeEnum getLogicalValue (byte numericalValue)
    {
       if (numericalValue < 0x02) 
          return (MessageTypeEnum(numericalValue)); 
       else
          return MessageTypeEnum.identify;
    }
}

I could also create a class without an enum, but with static members.

Either way there is one Problem: If someone tries to dispatch a packet, he might use

if (messageBytes[x] == (byte)MessageTypeEnum.identify) {
    // do stuff
}

But messageByte[x] could be anything between 0x02 and 0xFF, so "hitting" the value specified in the enum would be pure luck. On the other side I want the enum (or static member) to be public for easy message-building.

Can I somehow enforce the use of my getLogicalValue()-Function? Is there a more elegant solution?

All I want is an easy and well-structured way to link logical values to numerical values in a n:m relation. Especially as the given protocol has many such cases and I would like to keep my code neat.

Thanks for your help and time :)

Janis

like image 792
Janis Avatar asked Jan 27 '15 18:01

Janis


2 Answers

I recommend you to drop the idea of using enums and create a custom type for this.

It could be either struct or class; it doesn't matter. You could solve the equals problem by overloading the == operator and providing custom implementation.

Something like this:

public class MessageType
{
    private readonly byte value;
    private MessageType(byte value)
    {
        this.value = value;
    }

    public static readonly MessageType Get = new MessageType(0);
    public static readonly MessageType Set = new MessageType(1);
    public static readonly MessageType Identify = new MessageType(2);


    public static bool operator ==(MessageType m, byte b)
    {
        if (object.ReferenceEquals(m, null))
            return false;

        if (m.value == 2 && b >= 2 && b <= 0xff)//I think <= check is redundant
            return true;
        return m.value == b;
    }

    public static bool operator !=(MessageType m, byte b)
    {
        return !(m == b);
    }
   //Need to implement Equals, GetHashCode etc
}

Don't forget to implement Equals and GetHashCode for consistency in equals implementation.

like image 53
Sriram Sakthivel Avatar answered Sep 22 '22 10:09

Sriram Sakthivel


Actually I would use the enum values as identifiers only and not as the actual values. Something like this:

class MessageType {
    public enum MessageTypeEnum {
        get, 
        set, 
        identify
    }

    public static MessageTypeEnum getLogicalValue (byte numericalValue)
    {
       if (numericalValue == 0x00) 
          return MessageTypeEnum.get; 
       else if (numericalValue == 0x01)
          return MessageTypeEnum.set;
       else
          return MessageTypeEnum.identify;
    }
}

And use it this way:

if (MessageType.getLogicalValue(messageBytes[x]) == MessageTypeEnum.identify) {
    // do stuff
}

You can of course use a switch instead of if... else if..., that depends on your personal preference and needs.

As stated in other answer, if you want to use a direct comparison, you'll need to create a custom class and implement the equality comparison to what you need.

like image 34
Josh Part Avatar answered Sep 20 '22 10:09

Josh Part