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
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With