为查看数组而创建的索引器看不到对数组所做的更改
Indexer created to look at array doesn't see changes made to array
我是 c# 的新手,我正在为我设计的电路板创建串行端口 class。其中 class 包含 open/close 连接到开发板的串行端口的方法。它还应该从板上读取消息并将消息从 UI 写入板(我正在使用表单应用程序输入和显示值)。
我读取内部输入缓冲区并将字节放入我自己的软件缓冲区,当消息完成时,这将提示表单分析消息...
为此,我创建了一个索引器来指向数组(从表单中)并获取它想要的字节。
uint[] serialPortReceiveBuffer = new uint[3];
public delegate void Del();
Del promptFormAction = Form1.MsgReceived;
public void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
for (int i = 0; i <= 2; i++)
{
serialPortReceiveBuffer[i] = (uint)serialPort1.ReadByte();
}
promptFormAction();
}
public uint this[uint i]
{
get { return serialPortReceiveBuffer[i]; }
}
这是我的pcbSerialPortclass里面的代码,在Form1class里面相关的代码如下:
public static void MsgReceived()
{
Form1 _frm = new Form1();
_frm.analyzeIncomingMessage();
}
public void analyzeIncomingMessage()
{
if (PCB[0] == 63)
{
setBoardDesignator(PCB[1], PCB[2]);
}
}
我的问题是,当我使用索引器访问 serialPortReceiveBuffer
时,它没有看到我在将接收到的字节放入同一数组时对其所做的更改。例如,当我收到我自己的协议字符串时 --> "?10" 缓冲区填充 [63][49][48]
虽然当我尝试使用索引器访问此缓冲区时我得到 [0][0][0]
请问有人能帮忙吗?另外,我知道可能还有其他一些事情我可以做得更好,所以如果您有任何一般性提示会很棒。也用我可能理解的语言。我刚刚开始了解 C# 的许多方面,过去一年我一直在做嵌入式软件,但我不认为自己是一个称职的程序员。
谢谢
根据您的代码,我不太确定您在表单中使用的 PCB
对象实际上是接收数据的对象。很可能您正在使用两个不同的实例,尤其是当您在数据进入时创建 Form1
的新实例时!
(编辑:从您对问题的评论可以清楚地看出这正是问题所在。按照这些说明关闭您想要的内容)。
我建议您重新设计代码,将收到的消息作为事件传递给现有的表单实例,而不是像现在那样做。您可能 运行 遇到的另一个问题是您认为您获得的数据将被下一条传入的消息覆盖,因为 DataReceived
事件是异步的。
我会声明一个表单实例可以订阅的事件,将要分析的数据传递到事件中:
public class MessageReceivedEventArgs: EventArgs
{
public MessageReceivedEventArgs(byte[] data) : base()
{
Data = data;
}
public byte[] Data
{
get;
private set;
}
}
public event EventHandler<MessageReceivedEventArgs> MessageReceived;
然后,我将按如下方式更改您的 DataReceived
事件:
public void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
for (int i = 0; i <= 2; i++)
{
serialPortReceiveBuffer[i] = (uint)serialPort1.ReadByte();
}
byte[] dataCopy = new byte[serialPortReceiveBuffer.Length];
Array.Copy(serialPortReceiveBuffer, dataCopy, dataCopy.Length);
promptFormAction(dataCopy);
}
private void promptForAction(byte[] data)
{
if (MessageReceived != null)
MessageReceived(this, new MessageReceivedEventArgs(data));
}
此外,我会将 serialPortReceiveBuffer
完全保密给那个 class,正如我所说,如果您不这样做,您可能 运行 会遇到同步问题。这就是我在将数组传递给事件之前复制数组的原因。
此更改允许任何订阅者在您意识到有新数据传入时注册通知。
要使用它,Form1
应该如下所示(大致);
public class Form1
{
pcbSerialPort PCB; // The name of that class I don't know from your code
public Form1()
{
PCB = new pcbSerialPort();
PCB.MessageReceived += MessageReceived;
}
private void MessageReceived(object sender, pcbSerialPort.MessageReceivedEventArgs e)
{
analyzeIncomingMessage(e.Data);
}
private void analyzeIncomingMessage(byte[] data)
{
if (data[0] == 63)
{
setBoardDesignator(data[1], data[2]);
}
}
}
关于如何处理串行数据的另一条建议:您需要决定是循环读取串行端口还是依赖 DataReceived
事件。将循环放入事件中不是一个好主意,因为事件可能会在您等待时再次被调用。
您需要做的是创建一个缓冲区,从可用的串行端口获取所有信息。如果您没有足够的数据,请不要等待。而是在调用 DataReceived
时添加到缓冲区,并在存在足够数据时处理消息。
我认为 Thorsten 的回答很好,按照这些思路重新设计它会很有意义,但作为绝对最低限度,如果你想要创建一个新的 Form1
实例对于每条收到的消息,您需要将 pcbSerialPort
的实例传递给 MessageReceived
,然后传递给 Form1
class 的构造函数。类似于:
Action<pcbSerialPort> promptFormAction = Form1.MsgReceived;
public void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// as Thorsten noted, you need to rethink this loop anyway
// what if there aren't at least three bytes to read?
for (int i = 0; i <= 2; i++)
{
serialPortReceiveBuffer[i] = (uint)serialPort1.ReadByte();
}
promptFormAction(this);
}
还有你的静态方法:
public static void MsgReceived(pcbSerialPort pcb)
{
Form1 _frm = new Form1(pcb);
_frm.analyzeIncomingMessage();
}
你 Form1
的构造函数:
public Form1(pcbSerialPort pcb)
{
PCB = pcb;
}
我是 c# 的新手,我正在为我设计的电路板创建串行端口 class。其中 class 包含 open/close 连接到开发板的串行端口的方法。它还应该从板上读取消息并将消息从 UI 写入板(我正在使用表单应用程序输入和显示值)。
我读取内部输入缓冲区并将字节放入我自己的软件缓冲区,当消息完成时,这将提示表单分析消息...
为此,我创建了一个索引器来指向数组(从表单中)并获取它想要的字节。
uint[] serialPortReceiveBuffer = new uint[3];
public delegate void Del();
Del promptFormAction = Form1.MsgReceived;
public void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
for (int i = 0; i <= 2; i++)
{
serialPortReceiveBuffer[i] = (uint)serialPort1.ReadByte();
}
promptFormAction();
}
public uint this[uint i]
{
get { return serialPortReceiveBuffer[i]; }
}
这是我的pcbSerialPortclass里面的代码,在Form1class里面相关的代码如下:
public static void MsgReceived()
{
Form1 _frm = new Form1();
_frm.analyzeIncomingMessage();
}
public void analyzeIncomingMessage()
{
if (PCB[0] == 63)
{
setBoardDesignator(PCB[1], PCB[2]);
}
}
我的问题是,当我使用索引器访问 serialPortReceiveBuffer
时,它没有看到我在将接收到的字节放入同一数组时对其所做的更改。例如,当我收到我自己的协议字符串时 --> "?10" 缓冲区填充 [63][49][48]
虽然当我尝试使用索引器访问此缓冲区时我得到 [0][0][0]
请问有人能帮忙吗?另外,我知道可能还有其他一些事情我可以做得更好,所以如果您有任何一般性提示会很棒。也用我可能理解的语言。我刚刚开始了解 C# 的许多方面,过去一年我一直在做嵌入式软件,但我不认为自己是一个称职的程序员。
谢谢
根据您的代码,我不太确定您在表单中使用的 PCB
对象实际上是接收数据的对象。很可能您正在使用两个不同的实例,尤其是当您在数据进入时创建 Form1
的新实例时!
(编辑:从您对问题的评论可以清楚地看出这正是问题所在。按照这些说明关闭您想要的内容)。
我建议您重新设计代码,将收到的消息作为事件传递给现有的表单实例,而不是像现在那样做。您可能 运行 遇到的另一个问题是您认为您获得的数据将被下一条传入的消息覆盖,因为 DataReceived
事件是异步的。
我会声明一个表单实例可以订阅的事件,将要分析的数据传递到事件中:
public class MessageReceivedEventArgs: EventArgs
{
public MessageReceivedEventArgs(byte[] data) : base()
{
Data = data;
}
public byte[] Data
{
get;
private set;
}
}
public event EventHandler<MessageReceivedEventArgs> MessageReceived;
然后,我将按如下方式更改您的 DataReceived
事件:
public void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
for (int i = 0; i <= 2; i++)
{
serialPortReceiveBuffer[i] = (uint)serialPort1.ReadByte();
}
byte[] dataCopy = new byte[serialPortReceiveBuffer.Length];
Array.Copy(serialPortReceiveBuffer, dataCopy, dataCopy.Length);
promptFormAction(dataCopy);
}
private void promptForAction(byte[] data)
{
if (MessageReceived != null)
MessageReceived(this, new MessageReceivedEventArgs(data));
}
此外,我会将 serialPortReceiveBuffer
完全保密给那个 class,正如我所说,如果您不这样做,您可能 运行 会遇到同步问题。这就是我在将数组传递给事件之前复制数组的原因。
此更改允许任何订阅者在您意识到有新数据传入时注册通知。
要使用它,Form1
应该如下所示(大致);
public class Form1
{
pcbSerialPort PCB; // The name of that class I don't know from your code
public Form1()
{
PCB = new pcbSerialPort();
PCB.MessageReceived += MessageReceived;
}
private void MessageReceived(object sender, pcbSerialPort.MessageReceivedEventArgs e)
{
analyzeIncomingMessage(e.Data);
}
private void analyzeIncomingMessage(byte[] data)
{
if (data[0] == 63)
{
setBoardDesignator(data[1], data[2]);
}
}
}
关于如何处理串行数据的另一条建议:您需要决定是循环读取串行端口还是依赖 DataReceived
事件。将循环放入事件中不是一个好主意,因为事件可能会在您等待时再次被调用。
您需要做的是创建一个缓冲区,从可用的串行端口获取所有信息。如果您没有足够的数据,请不要等待。而是在调用 DataReceived
时添加到缓冲区,并在存在足够数据时处理消息。
我认为 Thorsten 的回答很好,按照这些思路重新设计它会很有意义,但作为绝对最低限度,如果你想要创建一个新的 Form1
实例对于每条收到的消息,您需要将 pcbSerialPort
的实例传递给 MessageReceived
,然后传递给 Form1
class 的构造函数。类似于:
Action<pcbSerialPort> promptFormAction = Form1.MsgReceived;
public void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// as Thorsten noted, you need to rethink this loop anyway
// what if there aren't at least three bytes to read?
for (int i = 0; i <= 2; i++)
{
serialPortReceiveBuffer[i] = (uint)serialPort1.ReadByte();
}
promptFormAction(this);
}
还有你的静态方法:
public static void MsgReceived(pcbSerialPort pcb)
{
Form1 _frm = new Form1(pcb);
_frm.analyzeIncomingMessage();
}
你 Form1
的构造函数:
public Form1(pcbSerialPort pcb)
{
PCB = pcb;
}