为什么我的异步方法不等待 "serialPort = await SerialDevice.FromIdAsync()"?
Why does my async method not wait on "serialPort = await SerialDevice.FromIdAsync()"?
我正在尝试制作一个 class 来初始化树莓派和 arduino 之间的串行连接。 class 还应该能够通过已建立的串行连接进行读写。
我使用的代码来自microsoft developers website。
using Windows.Storage.Streams;
using Windows.Devices.Enumeration;
using Windows.Devices.SerialCommunication;
public async void Serial()
{
/* Find the selector string for the serial device */
string aqs = SerialDevice.GetDeviceSelector("UART0");
/* Find the serial device with our selector string */
var dis = await DeviceInformation.FindAllAsync(aqs);
/* Create an serial device with our selected device */
SerialDevice SerialPort = await SerialDevice.FromIdAsync(dis[0].Id);
/* Configure serial settings */
SerialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
SerialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);
SerialPort.BaudRate = 9600;
SerialPort.Parity = SerialParity.None;
SerialPort.StopBits = SerialStopBitCount.One;
SerialPort.DataBits = 8;
/* Write a string out over serial */
string txBuffer = "Hello Serial";
DataWriter dataWriter = new DataWriter();
dataWriter.WriteString(txBuffer);
uint bytesWritten = await SerialPort.OutputStream.WriteAsync(dataWriter.DetachBuffer());
/* Read data in from the serial port */
const uint maxReadLength = 1024;
DataReader dataReader = new DataReader(SerialPort.InputStream);
uint bytesToRead = await dataReader.LoadAsync(maxReadLength);
string rxBuffer = dataReader.ReadString(bytesToRead);
}
我为 Package.appxmanifest 添加了串行通信功能。
<Capabilities>
<DeviceCapability Name="serialcommunication">
<Device Id="any">
<Function Type="name:serialPort" />
</Device>
</DeviceCapability>
</Capabilities>
到目前为止一切正常。 Raspberry 成功发送和接收另一端Arduino 的消息。
现在我尝试分别执行这些步骤。先初始化串口连接,这样读写函数就可以在应用中需要的时候使用了。
主页
namespace SerialUART
{
public sealed partial class MainPage : Page
{
private SerialController serial = new SerialController();
public MainPage()
{
this.InitializeComponent();
serial.Write();
serial.Read();
}
}
}
串行控制器
using Windows.Devices.Enumeration;
using Windows.Devices.SerialCommunication;
using Windows.Storage.Streams;
namespace SerialUART
{
class SerialController
{
private SerialDevice SerialPort;
private DataWriter dataWriter;
private DataReader dataReader;
public SerialController()
{
InitSerial();
}
private async void InitSerial()
{
string aqs = SerialDevice.GetDeviceSelector("UART0");
var dis = await DeviceInformation.FindAllAsync(aqs);
SerialPort = await SerialDevice.FromIdAsync(dis[0].Id);
// The program does not wait here and executes Write()
// after Write() the following code will be executed
SerialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
SerialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);
SerialPort.BaudRate = 9600;
SerialPort.Parity = SerialParity.None;
SerialPort.StopBits = SerialStopBitCount.One;
SerialPort.DataBits = 8;
dataWriter = new DataWriter();
dataReader = new DataReader(SerialPort.InputStream);
}
public async void Read()
{
/* Read data in from the serial port */
const uint maxReadLength = 1024;
uint bytesToRead = await dataReader.LoadAsync(maxReadLength);
string rxBuffer = dataReader.ReadString(bytesToRead);
Debug.WriteLine(rxBuffer);
}
public async void Write()
{
/* Write a string out over serial */
string txBuffer = "Hello Serial";
dataWriter.WriteString(txBuffer);
uint bytesWritten = await SerialPort.OutputStream.WriteAsync(dataWriter.DetachBuffer());
}
}
}
此代码不等待serialPort、dataWriter 和dataReader 初始化。所以他们永远不会被分配到。
谁能给我解释一下为什么不等待串行连接?应该如何完成?
所有 async
方法 return void
- 这意味着它们开始执行,并且调用代码 没有简单的方法 等待直到它真正完成后再继续。一旦您在尚未完成的事情上使用 await
表达式,异步方法将 return 发送给调用者,并安排了一个延续,该延续将在可等待完成时执行。在你的情况下,你只是继续下一个语句。
相反,您应该创建异步方法 return Task
,并更改您的调用方法以等待异步方法完成后再继续。 优雅地很难做到这一点,因为在每种情况下,您都是从构造函数调用异步方法,而构造函数本身不能是异步的。您可能想考虑使用异步静态方法而不是在构造函数中执行工作,构造函数可以调用异步方法,等待它们,然后调用不执行任何实际工作的实际构造函数。
尽管如此,在您进行任何详细更改之前,您真的应该阅读更多关于 async
和 await
的内容 - 尝试在不理解它们的情况下使用它们会导致更多问题。
这是你的构造器:
public SerialController()
{
InitSerial();
}
它调用 InitSerial()
方法,其中有几个 await(s)。构造函数 return 立即生效,没有做任何需要做的事情。然后调用这些方法:
serial.Write();
serial.Read();
但是那些方法依赖于在 InitSerial
方法中执行的每一行代码,但显然它们没有。
解决它的一种方法是使 InitSerial
不是私有的(内部或 public)并使其成为 return Task
。当你调用它时,你需要等待它以便它已经执行完成。之后,您可以调用 serial.Write()
和 Serial.Read()
.
你应该避免 async void
。它们仅用于事件处理。对于其他方法 return Task
或 Task<T>
.
我正在尝试制作一个 class 来初始化树莓派和 arduino 之间的串行连接。 class 还应该能够通过已建立的串行连接进行读写。
我使用的代码来自microsoft developers website。
using Windows.Storage.Streams;
using Windows.Devices.Enumeration;
using Windows.Devices.SerialCommunication;
public async void Serial()
{
/* Find the selector string for the serial device */
string aqs = SerialDevice.GetDeviceSelector("UART0");
/* Find the serial device with our selector string */
var dis = await DeviceInformation.FindAllAsync(aqs);
/* Create an serial device with our selected device */
SerialDevice SerialPort = await SerialDevice.FromIdAsync(dis[0].Id);
/* Configure serial settings */
SerialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
SerialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);
SerialPort.BaudRate = 9600;
SerialPort.Parity = SerialParity.None;
SerialPort.StopBits = SerialStopBitCount.One;
SerialPort.DataBits = 8;
/* Write a string out over serial */
string txBuffer = "Hello Serial";
DataWriter dataWriter = new DataWriter();
dataWriter.WriteString(txBuffer);
uint bytesWritten = await SerialPort.OutputStream.WriteAsync(dataWriter.DetachBuffer());
/* Read data in from the serial port */
const uint maxReadLength = 1024;
DataReader dataReader = new DataReader(SerialPort.InputStream);
uint bytesToRead = await dataReader.LoadAsync(maxReadLength);
string rxBuffer = dataReader.ReadString(bytesToRead);
}
我为 Package.appxmanifest 添加了串行通信功能。
<Capabilities>
<DeviceCapability Name="serialcommunication">
<Device Id="any">
<Function Type="name:serialPort" />
</Device>
</DeviceCapability>
</Capabilities>
到目前为止一切正常。 Raspberry 成功发送和接收另一端Arduino 的消息。
现在我尝试分别执行这些步骤。先初始化串口连接,这样读写函数就可以在应用中需要的时候使用了。
主页
namespace SerialUART
{
public sealed partial class MainPage : Page
{
private SerialController serial = new SerialController();
public MainPage()
{
this.InitializeComponent();
serial.Write();
serial.Read();
}
}
}
串行控制器
using Windows.Devices.Enumeration;
using Windows.Devices.SerialCommunication;
using Windows.Storage.Streams;
namespace SerialUART
{
class SerialController
{
private SerialDevice SerialPort;
private DataWriter dataWriter;
private DataReader dataReader;
public SerialController()
{
InitSerial();
}
private async void InitSerial()
{
string aqs = SerialDevice.GetDeviceSelector("UART0");
var dis = await DeviceInformation.FindAllAsync(aqs);
SerialPort = await SerialDevice.FromIdAsync(dis[0].Id);
// The program does not wait here and executes Write()
// after Write() the following code will be executed
SerialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
SerialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);
SerialPort.BaudRate = 9600;
SerialPort.Parity = SerialParity.None;
SerialPort.StopBits = SerialStopBitCount.One;
SerialPort.DataBits = 8;
dataWriter = new DataWriter();
dataReader = new DataReader(SerialPort.InputStream);
}
public async void Read()
{
/* Read data in from the serial port */
const uint maxReadLength = 1024;
uint bytesToRead = await dataReader.LoadAsync(maxReadLength);
string rxBuffer = dataReader.ReadString(bytesToRead);
Debug.WriteLine(rxBuffer);
}
public async void Write()
{
/* Write a string out over serial */
string txBuffer = "Hello Serial";
dataWriter.WriteString(txBuffer);
uint bytesWritten = await SerialPort.OutputStream.WriteAsync(dataWriter.DetachBuffer());
}
}
}
此代码不等待serialPort、dataWriter 和dataReader 初始化。所以他们永远不会被分配到。
谁能给我解释一下为什么不等待串行连接?应该如何完成?
所有 async
方法 return void
- 这意味着它们开始执行,并且调用代码 没有简单的方法 等待直到它真正完成后再继续。一旦您在尚未完成的事情上使用 await
表达式,异步方法将 return 发送给调用者,并安排了一个延续,该延续将在可等待完成时执行。在你的情况下,你只是继续下一个语句。
相反,您应该创建异步方法 return Task
,并更改您的调用方法以等待异步方法完成后再继续。 优雅地很难做到这一点,因为在每种情况下,您都是从构造函数调用异步方法,而构造函数本身不能是异步的。您可能想考虑使用异步静态方法而不是在构造函数中执行工作,构造函数可以调用异步方法,等待它们,然后调用不执行任何实际工作的实际构造函数。
尽管如此,在您进行任何详细更改之前,您真的应该阅读更多关于 async
和 await
的内容 - 尝试在不理解它们的情况下使用它们会导致更多问题。
这是你的构造器:
public SerialController()
{
InitSerial();
}
它调用 InitSerial()
方法,其中有几个 await(s)。构造函数 return 立即生效,没有做任何需要做的事情。然后调用这些方法:
serial.Write();
serial.Read();
但是那些方法依赖于在 InitSerial
方法中执行的每一行代码,但显然它们没有。
解决它的一种方法是使 InitSerial
不是私有的(内部或 public)并使其成为 return Task
。当你调用它时,你需要等待它以便它已经执行完成。之后,您可以调用 serial.Write()
和 Serial.Read()
.
你应该避免 async void
。它们仅用于事件处理。对于其他方法 return Task
或 Task<T>
.