我正在用c#编写一个应用程序,它利用SerialPort
类与少数设备进行通信。现在我遇到的一个大问题是如何在那里正确释放资源,因为在尝试使用已经使用的串口时会立即出现异常。
由于通常情况下GC应该处理大部分工作,我有点想法还有什么可以尝试......
主要是我尝试了两件事(按照我的逻辑)应该做的工作。我使用基于会话的通信,因此我在每次通信之前和之后调用OpenPort
和ClosePort
方法 - 因此应该关闭端口。此外,我已经尝试将包含端口的对象设置为null - 但我仍然始终获得UnauthorizedAccessExceptions
- 尽管我100%确定已调用SerialPort.Close()
方法。
你们有没有更好的方法来释放端口,所以我不再得到那个例外?
编辑: 谢谢你的答案,但Dispose()的东西不起作用 - 我之前尝试过 - 也许我做错了虽然这样我的代码看起来像一个例子:
这实际上就像Øyvind建议的那样,虽然我刚刚添加了IDisposable
- 但是也不起作用:
所以这将是我的包装类:
class clsRS232 : IDisposable
{
public void clsRS232()
{
Serialport port = new Serialport("COM1",9600,Parity.none,8,Stopbits.one);
}
public void openPort()
{
port.Open();
}
public void sendfunc(string str)
{
port.Write(str);
}
public string readfunc()
{
port.ReadTo("\n");
}
public void Dispose()
{
port.Dispose();
}
}
现在每当我需要rs232通信时,我都会调用这样一个新实例:
clsRS232 test = new clsRS232;
test.openport();
test.sendfunc("test");
test.Dispose();
但是,这并不能改变什么 - 我仍然得到很多UnauthorizedAccessExceptions的 - 如果其他人是正确的(即的SerialPort类的Dispose()方法只包含SerialPort.Close()) - 阱那么我想我的天堂”我真的改变了我之前的方法,我有一个函数调用close();
感谢您的回答 - 仍然希望找到解决方案:)
答案 0 :(得分:8)
由于SerialPort
实现IDisposable
,您应该编写如下代码:
using( SerialPort port = new SerialPort( ... ) ){
//do what you need with the serial port here
}
这将确保在using
块的末尾释放串行端口,并且如果在using
块内发生异常则将其释放,因为using
block与try / finally块完全相同,它关闭/处置finally块内的SerialPort
。
修改强>
根据OP的需要,SerialPort
应保持开放的时间长于方法的时间范围。
在这种情况下,我会将与其自身类中的串行端口有关的整个逻辑包装起来。在类的构造函数中,打开串行端口,并编写方法来执行所需的操作。然后让这个类实现IDisposable
本身,并将SerialPort配置在您自己的Dispose
方法中。
这将使您更好地控制必须打开和关闭/处置串行端口的位置,并将串行端口逻辑包装到适当的类中。
如果您希望将端口保持打开一段时间不容易被代码块包含,那么您必须在完成后手动处理它,例如当使用它的函数关闭时或任何触发程序中com端口释放的内容。
编辑2
您当前的实施方式如下:
clsRS232 test = new clsRS232;
test.openport();
test.sendfunc("test");
test.Dispose();
这里的问题是如果sendfunc
以某种方式导致异常,它将永远不会被处理掉。从一开始就实现IDisposable
所获得的是,您可以将代码更改为:
using( clsRS232 test = new clsRS232 ){
test.openport();
test.sendfunc("test");
}
现在可以保证,无论Dispose
块内是否存在任何异常,都会为您的com端口调用using
。
答案 1 :(得分:3)
我知道这是非常古老的,但我遇到了同样的问题,这个解决方案对我有用,虽然它有点hacky。根据这个线程why is access to com port denied?,问题在于SerialPortClass中的一个错误。我创建了一个只打开端口一次的包装类,并为应用程序的生命周期创建类。然后将SerialPort放置在类的Dispose中,但使用以下命令打开:
private SerialPort KickerPort { get; set; }
.
.
.
private bool OpenPort()
{
//https://stackoverflow.com/questions/7219653/why-is-access-to-com-port-denied
//due to a bug in the SerialPort code, the serial port needs time to dispose if we used this recently and then closed
//therefore the "open" could fail, so put in a loop trying for a few times
int sleepCount = 0;
while (!TryOpenPort())
{
System.Threading.Thread.Sleep(100);
sleepCount += 1;
System.Diagnostics.Debug.Print(sleepCount.ToString());
if (sleepCount > 50) //5 seconds should be heaps !!!
{
throw new Exception(String.Format("Failed to open kicker USB com port {0}", KickerPort.PortName));
}
}
return true;
}
private bool TryOpenPort()
{
if (!KickerPort.IsOpen)
{
try
{
KickerPort.Open();
return true;
}
catch (UnauthorizedAccessException)
{
return false;
}
catch (Exception ex)
{
throw ex;
}
}
return true;
}
这称为:
try
{
if (OpenPort())
{
//do your thing here !
}
return false;
}
catch (Exception ex)
{
throw ex;
}
在我的测试中(我用它打开USB踢球器上的现金抽屉)我发现有时它会在第一时间打开,有时它会经过睡眠循环约20次,具体取决于最近的时间
答案 2 :(得分:1)
ØyvindBråthen提出的实现使用.NET中的IDisposable模式。在using块的末尾,调用SerialPort实例的Dispose函数,它将释放相关的非托管资源(即串口)
当你想要释放它时,自己调用port.Dispose()。