2010-12-06 12 views
5

私は、SerialPortクラスを使用していくつかのデバイスと通信するC#でアプリケーションを書いています。私が今直面してきた大きな問題は、すでに使用されているシリアルポートを使用しようとするとすぐに例外が発生するため、リソースを適切に解放する方法です。通常、GCは、私は他に何しようとするアイデアをちょっとだ仕事のほとんどの世話をする必要があるためシリアルポートを正しく解放する

...

は主に私が仕事を行う必要があります(私のロジックで)その2つのことを試してみました。私はセッションベースの通信を使用しているので、私はすべての通信の前後にOpenPortClosePortメソッドを呼び出します - したがって、ポートは閉じなければなりません。また、ポートを含むオブジェクトを後でnullに設定しようとしましたが、まだUnauthorizedAccessExceptionsを取得していますが、SerialPort.Close()メソッドが呼び出されたことを100%確信しています。

ポートを解放する方法がわかりましたので、私はその例外を取り止めますか?

EDIT:

: 答えてくれてありがとうしかし、廃棄()のものが動作していないが - ので、ここで私のコードがどのように見えるかの例ですけれども、多分、私が何か間違ったことをやっている - 私は前にいることをしようとしました

だからこれは私のラッパークラス次のようになります:

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通信を必要とする時はいつでも、私はCALのどちらかが、動作しません - それは私がちょうどIDisposableを追加したものの、Øyvindが提案かなり似実際ですこのようなラ新しいインスタンス:

clsRS232 test = new clsRS232; 
    test.openport(); 
    test.sendfunc("test"); 
    test.Dispose(); 

しかし、それは何も変更しません - 私はまだUnauthorizedAccessExceptionsの多くを得る - と他の男が(右だった場合SERIALPORTクラスの処分は、()のみSerialPort.Closeが含まれていること( )) - それでは、私は関数呼び出しclose()を持っていた以前のアプローチから何も変更していないと思います。あなたの答えのための

ありがとう - まだ解決策を見つけることを望ん:)

答えて

6

SerialPortIDisposableを実装しているので、あなたがこのようなコードを書く必要があります。

using(SerialPort port = new SerialPort(...)){ 
    //do what you need with the serial port here 
} 

は、これは確かの終わりということになりますusingブロックは解放され、usingブロックはfinallyブロック内のSerialPortを閉じる/廃棄するtry/finallyブロックとまったく同じなので、解放されるのはusingブロック内で例外が発生した場合です。

EDIT

はOPのニーズによるとSerialPortは、法の期限よりも長く開いたままにしてください。

その場合、私は自分のクラス内のシリアルポートと関係があるロジック全体をラップします。クラスのコンストラクタで、シリアルポートを開き、必要な操作を行うためのメソッドを記述します。次に、このクラスにIDisposableを実装させ、独自のDisposeメソッド内にSerialPortを配置します。

これにより、シリアルポートを開いたり閉じたりして、シリアルポートロジックを適切なクラスにラップする必要がある場所を、より適切に制御できます。

コードブロックに含まれていない期間、ポートを開いたままにしておきたい場合は、それを使用した関数が使用された場合など、手動で終了する必要がありますあなたのプログラムのcomポートのリリースを引き起こします。

EDIT 2

があなたの現在の実装では、このようなものです:

clsRS232 test = new clsRS232; 
test.openport(); 
test.sendfunc("test"); 
test.Dispose(); 

ここでの問題は、sendfuncが何らかの方法で例外が発生した場合、それが配置されることはありませんということです。あなたが最初の場所でIDisposableの実施から得る何を、あなたはこのように見えるようにコードを変更することができるということです。

using(clsRS232 test = new clsRS232){ 
test.openport(); 
test.sendfunc("test"); 
} 

今、あなたはDisposeusingの内側にかかわらず、すべての例外のあなたのcomポートのために呼び出されることが保証されていますブロック。

+0

速い答えに感謝するが、私は本当にそれをすることができない。私はシリアルポート通信に使用する独自のクラスで多くの独自のメソッドをラップしています - 彼らはすべて、クラスが最初に呼び出されたときに初期化される1つのポートを使用します。このようにしたい場合は、ポートを使用するすべてのメソッドにこのようなブロックを記述する必要があります。 – Lorenz

+0

クラスを作成したときからポートを開いたままにし、すべての操作が完了したときにポートを閉じるか、各操作の前後にポートへの接続を開いたり閉じたりしますか? –

+0

最初の1つ - 私のラッパークラスは、そのコンストラクタを介してSerialPortのインスタンスを開始します - これは、複数のメソッドを使って/ recieveなどで使用できますが、一度自分自身のclose()関数(一度はSerialPort.Close ())私は、Serialportを完全に自由に再インスタンス化したいと思っています。私が何かを書いた後にポートを閉じて、何かを受け取るために再び開くと、バッファが消えてしまいます。 – Lorenz

0

ØyvindBråthenが提案した実装は、.NETでIDisposableパターンを使用します。 usingブロックの最後にSerialPortインスタンスのDispose関数が呼び出され、関連付けられているアンマネージリソース(シリアルポート)が解放されます。

解放するときにポートを呼び出します。

+0

yep - Dispose()前に試してみました - 悲しいことに私の例外に関して何も変更されません:/ありがとう:) – Lorenz

2

私はこれが非常に古いことを知っていますが、私はちょうど同じ問題を遭遇しました。このスレッドwhy is access to com port denied?によると、問題はSerialPortClassのバグです。ポートを一度しか開くことのできないラッパークラスを作成し、アプリケーションの存続期間中のクラスを作成しました。 SERIALPORTは、そのクラスの処分に配置されているが、次を使用して開かれた。

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回である。

関連する問題