2011-12-17 22 views
1

我正在尝试编写自动将数据包序列化并反序列化为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)); 
    } 
} 

现在,反序列化,我需要查找的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]; 
    } 
} 

我正在寻找一种方法来自动生成每一个在编译时继承NetworkMessage类的ID字节。我可以在运行时使用Reflection来做到这一点,但是我不知道我是否可以相信每个机器的Ids都是相同的,并且对于像这样的东西使用Reflection似乎有点过分。

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

回答

3

而不是在编译时做它你可以在应用程序加载和缓存你找到或没有找到(我倾向于为了允许运行时扩展性)。下面是一些(未经测试)的代码,会发现所有“NetworkMessage”的孩子:如果你创建上使用NetworkMessage的任何子女,以确定消息ID字节属性

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

然后,您可以动态地发现您可以使用哪些类型来反序列化消息。

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

然后你可以如下创建一个网络消息类型:

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

我已经成功地使用这种通用设计理念上的几个不同的项目。


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

+0

我可以100%确定分配的Ids每次运行时都是一样的,并且可以在每台机器/硬件设置上进行分配?如果在客户端上反序列化的消息是错误的,那就不太好了。 –

+0

如果NetworkMessage实现上使用的属性指定应使用哪个消息ID来标识实现,那么是的。我将用示例属性和实现更新我的答案。 –

+0

@MindWorX:在编译时生成消息ID的问题在于它并不能真正解决您正在尝试解决的问题。在重建代码时,不能保证消息ID不会改变(不像每次运行时那样糟糕),除非您在管理中进行构建。我发现一致的解决问题的唯一方法是为属性标识的每个类都设置固定ID。 –