如何在编译时获得继承类的所有类型

本文关键字:类型 继承 编译 | 更新日期: 2023-09-27 18:18:04

我正在尝试编写自动序列化和反序列化数据包为NetworkMessage的网络代码。

以下是NetworkMessage

的代码
public abstract class NetworkMessage : ISerializable
{
    public readonly NetworkClient Client;
    protected NetworkMessage(NetworkClient client)
    {
        this.Client = client;
    }
    public abstract void GetObjectData(SerializationInfo info, StreamingContext context);
}

下面是示例NetworkMessageText的代码

public class NetworkMessageText : NetworkMessage
{
    public static readonly Byte Id = 0x01;
    public readonly String Message;
    public NetworkMessageText(NetworkClient client, String message)
        : base(client)
    {
        this.Message = message;
    }
    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("message", this.Message, typeof(String));
    }
}

现在,为了反序列化,我需要在dictionarybyte,Type>中查找Id,我在代码时已经在其中注册了不同的Id。

这是NetworkMessagesIds类为我做的

public static class NetworkMessageIds
{
    private static readonly Dictionary<Type, Byte> TypeIdDictionary = new Dictionary<Type, Byte>();
    private static readonly Dictionary<Byte, Type> IdTypeDictionary = new Dictionary<Byte, Type>(); 
    static NetworkMessageIds()
    {
        TypeIdDictionary.Add(typeof(NetworkMessageText), NetworkMessageText.Id);
        IdTypeDictionary.Add(NetworkMessageText.Id, typeof(NetworkMessageText));
    }
    public static Byte IdFromType(Type type)
    {
        return TypeIdDictionary[type];
    }
    public static Type TypeFromId(Byte id)
    {
        return IdTypeDictionary[id];
    }
}

我要找的是一种方法来自动生成Id字节的每个类在编译时继承NetworkMessage。我可以在运行时使用反射来做,但是我不知道我是否可以相信每台机器的id每次都是相同的,并且对于这样的事情使用反射似乎有点过度。

或者,对具有相同结果的不同方法的建议是受欢迎的,我基本上需要的是一个易于扩展的解决方案,其中"最终用户"只需要继承NetworkMessage以便他们的代码与网络解决方案一起工作。

如何在编译时获得继承类的所有类型

与其在编译时执行,不如在应用程序加载时执行,然后缓存找到的内容(为了允许运行时可扩展性,我倾向于不这样做)。下面是一些(未经测试的)代码,它将找到'NetworkMessage'的所有子节点:

var knownMessageTypes = AppDomain.CurrentDomain.GetAssemblies().ToList().ForEach(a => a.GetTypes().ToList().Where(t => t.IsSubclassOf(typeof(NetworkMessage)));

然后,如果您创建一个属性用于NetworkMessage的任何子节点来标识消息ID字节,您可以动态地发现您可以使用哪些类型来反序列化消息。

[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple=false)]
public class NetworkMessageAttribute : Attribute
{
    public byte MessageID { get; set }
}

那么您可以创建一个网络消息类型,如下所示:

[NetworkMessage(MessageID = 0x01)]
public class ExampleNetworkMessage : NetworkMessage

我已经在几个不同的项目中成功地使用了这个一般的设计概念。


编辑:如果你真的想实现你的目标,你已经设计了上面它可以实现与上述代码类似的方法。只需将其放入控制台应用程序中,该应用程序将生成一个消息定义列表文件,供应用程序读取,并将其设置为项目中的构建后活动