是否可以基于ID(ushort)创建结构而无需装箱和反射?

时间:2019-03-28 12:38:06

标签: c#

我有一个byte [],其中前两个字节是ushort,它提供一个ID,该ID告诉我数组其余部分包含的数据类型。基于此ID,我需要创建一个具有正确类型的结构以填充接收到的数据。

现在我以为我可能可以使用Dictionary,在启动时填充它,然后通过它获得正确的类型,但这会涉及很多反射和装箱,因为我要处理很多byte []。

有没有可能的解决方法,无需装箱和反射即可根据ushort ID创建所需的structtype?

编辑:

public struct TestMessage
    {
        public const ushort typeCode = (ushort)Enums.MessageOpcodes.TestMessage;    
        public uint testuInt { internal set; get; }
        public ushort testuShort { internal set; get; }
        public ulong testuLong { internal set; get; }

        public TestMessage(uint uInt, ushort uShort, ulong uLong)
        {
            testuInt = uInt;
            testuShort = uShort;
            testuLong = uLong;
        }
    }
public static ReadOnlyDictionary<ushort, object> messageTypes;

private static void PopulateMessageDict()
        {
            var tempMessageTypes = new Dictionary<ushort, object>();

            tempMessageTypes.TryAdd(TestMessage.typeCode, new TestMessage());
            messageTypes = new ReadOnlyDictionary<ushort, object>(tempMessageTypes);
        }

public void TryAdd(this Dictionary<ushort, object> dictionary, ushort key, object value)
        {
            if (!dictionary.ContainsKey(key))
            {
                dictionary.Add(key, value);                
            }
            else
            {
                Debug.Log("Key already exists in dictionary.");
            }
        }

1 个答案:

答案 0 :(得分:0)

因此,根据您的评论,我认为您根本不需要字典。

您说过要占用一些字节,查看前两个以确定消息类型,然后反序列化为正确类型的消息,然后以特定于该类型的方式对其进行处理。

因此,从高度上讲,您想要的是:

var opCode = (Enums.MessageOpcodes)(data[0] << 8 | data[1]);
switch (opCode)
{
    case Enums.MessageOpcodes.TestMessage:
        ProcessTestMessage(data);
        break;
    case Enums.MessageOpcodes.VectorMessage:
        ProcessVectorMessage(data);
        break;        
}

然后,您的ProcessTestMessage方法反序列化为TestMessage结构,然后对其进行处理;同样,您的ProcessVectorMessageVectorMessage结构。

您可以概括一下:

interface IMessageProcessor
{
    Enums.MessageOpcodes Opcode { get; }
    void DeserializeAndProcess(byte[] data);
}

然后:

class TestMessageProcessor : IMessageProcessor
{
    public Enums.MessageOpcodes Opcode => Enums.MessageOpcodes.TestMessage;
    public void DeserializeAndProcess(byte[] data)
    {
        // Deserialize into a TestMessage
        // Process
    }
}

然后您就拥有了Dictionary<Enums.MessageOpcodes, IMessageProcessor>(或者由于密钥是IMessageProcessor的属性,您可以使用KeyedCollection):

class MessageProcessorLookup : KeyedCollection<Enums.MessageOpcodes, IMessageProcessor>
{
    public override Enums.MessageOpcodes GetKeyForItem(IMessageProcessor item) => item.Opcode;
}

然后:

var lookup = new MessageProcessorLookup() { new TestMessageProcessor(), .... };
...
lookup[opcode].DeserializeAndProcess(data);

最终,如果您有一堆不同的结构,而又不想将它们装箱,则不能的代码表明“将数据反序列化为合适的结构-我不知道”不在乎是什么-然后将其还给我”,因为您将不得不将结构装箱以将其还给我。同样,您不能说“将数据反序列化为适当的结构,然后将其推送到处理所有消息类型的ConcurrentQueue上”,而无需装箱。所有处理都必须是“仅向前”的,使用反序列化为struct的方法,然后调用处理它的方法。