2013-03-12 1 views
1

내 VB.NET 프로그램에서 직렬 포트에 연결된 장치의 명령 응답을 읽는 중입니다. 현재 명령 세트는 고정되어 있지만 앞으로 새로운 명령이 추가 될 수도 있습니다. 거대한 switch/if-then-else 문보다 더 우아한 무언가가 있습니까? 각 명령을 읽고 그 객체를 만들 때 사용할 수 있습니까? 나는 기본 "명령"클래스를 가지고 있지만 각 명령이 가지고있는 특별한 기능을위한 클래스를 파생 시켰습니다.VB.NET의 직렬 포트에서 명령 객체를 우아하게 만드는 방법은 무엇입니까?

커맨드 세트에 새로운 개체가 추가 될 때마다 거대한 switch 문을 업데이트하지 않는 우아한 솔루션을 만들기를 바랬습니다.

답변

4

메시지의 형식과 어떻게 역 직렬화하는지에 따라 다릅니다. VB.NET을 사용하지 않았으므로이 예제를 C#으로 작성했지만 쉽게 변환 할 수 있어야합니다.

각 명령은 ICommand 인터페이스를 구현하며 일부 CommandBase 구현 클래스에서 파생됩니다. CommandBase은 각 명령 유형에 대해 고유 한 MessageId 추상 속성을 정의합니다 (상수를 사용할 수도 있음). 이 ID는 유선의 메시지 머리글의 일부이기 때문에 장치에서 오는 명령을 알 수 있습니다.

이제 장치에서 메시지 ID를 얻을 :

int msgId = ... // what came from the device 
Type cmdType = GetTypeForMessage(msgId); // get the corresponding implementation 
ICommand cmd = (Command)Activator.CreateInstance(cmdType); // crate an instance 
cmd.Deserialize(buffer); // or whatever way you do the serialization 
cmd.Execute(); // run the command 

당신은 이전에 설정 한지도에서 올바른 유형 얻을 : 이제

Type GetTypeForMessage(int msgId) { 
    // m_commandMap is Dictionary<int, Type> 
    return m_commandMap[msgId]; 
} 

을 남은 문제는 어떻게 설정 m_commandMap에 . 한 가지 방법은 일부 CommandBase 클래스에서 파생 된 모든 클래스를 자동으로 등록하는 것입니다. 당신은 시작에 같은 것을 할 :

// find all types in this assembly 
    Assembly assembly = Assembly.GetExecutingAssembly(); 
    foreach (var type in assembly.GetTypes()) { 
    if(typeof(CommandBase).IsAssignableFrom(type)) { // which derive from CommandBase 
     CommandBase cmd = (CommandBase) Activator.CreateInstance(type); 
     m_commandMap[cmd.MessageId] = type; 
     // I would make MessageId a static constant on class and read it 
     // using reflection, so I don't have to instantiate an object 
    }      
    } 

을 이제 새로운 명령을 구현해야 할 때, 당신이 할 일은 그것을 정의 할 수 있습니다 :

class NewCommand : CommandBase { 
    public override int MessageId { get { return 1234; } } 
    // or preferably: public const int MessageId = 1234; 
    // the rest of the command: ... 
} 

이 자동으로 시작시 등록에 사용됩니다 해당 ID가 장치에서 오는 경우 역 직렬화.

관련 문제