2011-12-17 4 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)); 
    } 
} 

이제 샘플 코드입니다 Byte, >을 입력하십시오. 여기서 코드 타임에 다른 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을 사용하여 런타임시이를 수행 할 수 있었지만, Id가 모든 머신마다 똑같을 것이라고 믿을 수 있는지, 그리고 Reflection을 사용하는 것이 이와 같이 약간 과장된 것처럼 보일지 모르겠다.

다른 접근 방식을 제안해도 동일한 결과를 얻을 수 있습니다. 기본적으로 필요한 것은 "최종 사용자"가 코드를 네트워킹 솔루션과 함께 사용하기 위해 상속해야하는 확장형 솔루션입니다.

답변

3

컴파일 시간에 수행하는 대신 응용 프로그램로드 및 캐시에서 수행 할 수 있습니다 (런타임 확장 성을 허용하지 않는 경향이 있음). 당신이 메시지 ID 바이트를 식별 할 수 NetworkMessage의 자식에서 사용하기 위해 속성을 만들 경우 다음

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

동적으로 발견 할 수 있습니다 : 여기 NetworkMessage '의 모든 아이를 찾을 일부 (테스트되지 않은) 코드는 메시지를 deserialize하는 데 사용할 수있는 유형. 다음과 같이

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

그럼 당신은 네트워크 메시지 유형을 만들 수 있습니다

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

나는 여러 가지 프로젝트 성공이 일반적인 디자인 개념을 사용했습니다.


편집 : 위의 코드와 유사한 접근법을 사용하여 위에서 설명한대로 목표를 달성하고 싶다면. 그냥 응용 프로그램에서 읽을 메시지 정의 목록 파일을 생성하고 프로젝트의 게시 빌드 활동으로 설정하는 콘솔 응용 프로그램에 넣으십시오.

+0

할당 된 ID가 실행될 때마다 매번 컴퓨터/하드웨어 설정이 가능한지 100 % 확신 할 수 있습니까? 클라이언트에서 메시지를 잘못 직렬화 한 경우 좋지 않습니다. –

+0

NetworkMessage 구현에 사용 된 속성이 구현을 식별하는 데 사용해야하는 메시지 ID를 지정하면 예. 샘플 속성 및 구현을 사용하여 답변을 업데이트하겠습니다. –

+0

@MindWorX : 컴파일 할 때 메시지 ID를 생성 할 때의 문제는 해결하려고하는 문제를 실제로 해결하지 못한다는 것입니다. 코드를 다시 빌드 할 때 메시지 ID가 변경되지 않을 것이라고 보장 할 수는 없습니다 (관리자가 빌드하지 않는 한 각 실행마다 나쁘지는 않습니다).일관되게 문제를 완화하는 유일한 방법은 속성으로 식별 된 각 클래스에 대한 고정 ID를 갖는 것입니다. –

관련 문제