问题描述
我正在编写一个应用程序,它运行脚本插件来自动化用户过去必须通过串行终端手动执行的操作。所以,我基本上是在代码中实现串行终端的功能。终端的功能之一是发送一个命令,该命令启动终端从设备接收连续流数据,直到用户按下空格键,然后停止数据流。当数据流传输时,用户会在其他设备上的另一个应用程序中设置一些值,并观察终端中流传输的数据的变化。
现在,流数据可以采用不同的形状,具体取决于发送的特定命令。例如,一个响应可能如下所示:
---RESPONSE HEADER---
HERE: 1
ARE: 2 SOME:3
VALUES: 4
---RESPONSE HEADER---
HERE: 5
ARE: 6 SOME:7
VALUES: 8
....
另一个可能看起来像:
here are some values
in cols and rows
....
所以,我的想法是根据我发送的命令使用不同的解析器。所以,我做了以下事情:
public class Terminal
{
private SerialPort port;
private IResponseHandler pollingResponseHandler;
private object locker = new object();
private List<Response1Clazz> response1;
private List<Response2Clazz> response2;
//setter omited for brevity
//get snapshot of data at any point in time while response is polling.
public List<Response1Clazz> Response1 {get { lock (locker) return new List<Response1Clazz>(response1); }
//setter omited for brevity
public List<Response2Clazz> Response2 {get { lock (locker) return new List<Response1Clazz>(response2); }
public Terminal()
{
port = new SerialPort(){/*initialize data*/}; //open port etc etc
}
void StartResponse1Polling()
{
Response1 = new List<Response1Clazz>();
Parser<List<Response1Clazz>> parser = new keyvalueParser(Response1); //parser is of type T
pollingResponseHandler = new PollingResponseHandler(parser);
//write command to start polling response 1 in a task
}
void StartResponse2Polling()
{
Response2 = new List<Response2Clazz>();
Parser<List<Response2Clazz>> parser = new RowColumnParser(Response2); //parser is of type T
pollingResponseHandler = new PollingResponseHandler(parser); // this accepts a parser of type T
//write command to start polling response 2
}
OnSerialDataReceived(object sender,Args a)
{
lock(locker){
//do some processing yada yada
//we pass in the serial data to the handler,which in turn delegates to the parser.
pollingResponseHandler.Handle(processedSerialData);
}
}
}
类的调用者将类似于
public class Plugin : BasePlugin
{
public override void PluginMain()
{
Terminal terminal = new Terminal();
terminal.StartResponse1Polling();
//update some other data;
Response1Clazz response = terminal.Response1;
//process response
//update more data
response = terminal.Response1;
//process response
//terminal1.StopPolling();
}
}
我的问题很笼统,但我想知道这是否是处理这种情况的最佳方法。现在我需要传入一个我想要修改的对象/列表,它是通过副作用修改的。出于某种原因,这感觉有点难看,因为代码中确实没有迹象表明这是正在发生的事情。我这样做纯粹是因为“开始”方法是知道要创建哪个解析器以及要更新哪些数据的位置。也许这是犹太洁食,但我认为值得询问是否有另一种/更好的方法。或者至少是一种更好的方式来表明“处理”方法会产生副作用。
谢谢!
解决方法
我在修改作为参数接收的 List<>
时没有发现问题。它不是世界上最美丽的东西,但它很常见。遗憾的是,C# 没有用于参数的 const
修饰符(将此与 C/C++ 进行比较,除非您将参数声明为 const
,否则该方法可以对其进行修改)。您只需为参数指定一个不言自明的名称(例如 outputList
),并在方法上添加注释(您知道,xml 注释块,例如 /// <param name="outputList">This list will receive...</param>
)。
要给出更完整的响应,我需要查看整个代码。您省略了 Parser
的示例和 Handler
的示例。
相反,我发现您在 lock
中的 { lock (locker) return new List<Response1Clazz>(response1); }
有问题。考虑到您然后执行 Response1 = new List<Response1Clazz>();
,但 Response1
只有一个 getter。