C# 替代 n:m 关系的枚举

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

枚举中的值范围有多个线程(不可能)。 但是我有以下问题并搜索最佳解决方案,其中 none 所提供的曾经让我非常满意。

协议规范说明消息的字节[x],即消息类型,具有以下可能的值(幻想值):

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

所以只有 3 个不同的逻辑选项,最好在枚举中处理。但是n个逻辑选项中的一个有m个不同的数值对应物,这是不可能在枚举中处理的。

对于这样的问题,最好(最干净)的解决方案是什么? 我可以建一个 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;
    }
}

我也可以创建一个没有枚举但有静态成员的 class。

无论哪种方式都有一个问题:如果有人试图发送数据包,他可能会使用

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

但是 messageByte[x] 可以是 0x02 和 0xFF 之间的任何值,因此 "hitting" 枚举中指定的值纯属运气。另一方面,我希望枚举(或静态成员)为 public 以便于构建消息。

我能否以某种方式强制使用我的 getLogicalValue() 函数? 有没有更优雅的解决方案?

我想要的只是一种简单且结构良好的方法,可以将 link 逻辑值转换为 n:m 关系中的数值。特别是因为给定的协议有很多这样的情况,我想保持我的代码整洁。

感谢您的帮助和时间:)

贾尼斯

实际上我只会将枚举值用作标识符而不是实际值。像这样:

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

并这样使用:

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

您当然可以使用switch代替if... else if...,这取决于您的个人喜好和需要。

如其他答案所述,如果您想使用直接比较,则需要创建自定义 class 并根据需要实施相等比较。

我建议您放弃使用枚举的想法并为此创建一个自定义类型。

可以是struct,也可以是class;没关系。您可以通过重载 == 运算符并提供自定义实现来解决等于问题。

像这样:

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
}

不要忘记实施 EqualsGetHashCode 以确保 equals 实施的一致性。

你可以重构方法签名并执行以下操作,它会通过传入值告诉你它实际上是哪个 enum 看看我刚刚为你重构的方法以及如何调用它以下

public static string getLogicalValue(byte numericalValue)
{
    Type type = numericalValue.GetType();
    var name = Enum.GetName(typeof(MessageTypeEnum), numericalValue);
    if (numericalValue < 0x02)
        return name;
    else
        return MessageTypeEnum.identify.ToString();
}

像这样调用静态方法

var enumValue = getLogicalValue(0x02);

return 字符串将是 identify 或者,如果您想执行 switch/case 语句,您也可以执行以下操作

    public static string getLogicalValue(byte numericalValue)
    {
        Type type = numericalValue.GetType();
        var name = Enum.GetName(typeof(MessageTypeEnum), numericalValue);
        switch(numericalValue)
        {
            case 0x00:
                {
                    name= (MessageTypeEnum.get.ToString());
                    break;
                }
            case 0x01:
                {
                    name= (MessageTypeEnum.set.ToString());
                    break;
                }

             default:   
                {
                    name= (MessageTypeEnum.identify.ToString());
                    break;
                }
        }
        return name;
    }