在我的VB.NET程序中,我正在讀取連接到串行端口的設備的命令響應。目前,這個命令集是固定的,但將來可能會添加新的命令。是否有比我可以用來讀取每個命令併爲它們創建對象的巨大開關/ if-then-else語句更優雅的東西?我有一個基本的「命令」類,但每個命令擁有特殊功能的派生類。如何在VB.NET中優雅地創建從串口讀入的命令對象?
我曾希望做出一個優雅的解決方案,避免每次將新對象添加到命令集時更新巨大的switch語句。
在我的VB.NET程序中,我正在讀取連接到串行端口的設備的命令響應。目前,這個命令集是固定的,但將來可能會添加新的命令。是否有比我可以用來讀取每個命令併爲它們創建對象的巨大開關/ if-then-else語句更優雅的東西?我有一個基本的「命令」類,但每個命令擁有特殊功能的派生類。如何在VB.NET中優雅地創建從串口讀入的命令對象?
我曾希望做出一個優雅的解決方案,避免每次將新對象添加到命令集時更新巨大的switch語句。
這取決於你的消息在網上的格式以及你如何反序列化它們。 我會做這樣的事情(例如在C#中,因爲我不使用VB.NET,但它應該很容易轉換)。
每個命令都實現了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來自設備,則反序列化。