2011-12-17 82 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。 –