2011-08-13 31 views
4

IDisposableにキャストする理由Dispose()Dispose()を呼び出す前にIDisposableにキャスト

public interface ITransaction : IDisposable 
{} 
. 
. 
. 

//in some other class: 
public void EndTransaction(ITransaction transaction) 
{ 
    if (transaction != null) 
    { 
      (transaction as IDisposable).Dispose(); 
      // is the following code wrong? transaction.Dispose() 

      transaction = null; 
    } 
} 

これはITransactionの具体的な実装の一つである:

public class NHibernateTransaction : ITransaction 
{ 

    public NHibernateTransaction(NHibernate.ITransaction transaction) 
    { 
      this.Transaction = transaction; 
    } 

    protected NHibernate.ITransaction Transaction { get; private set; } 

    public void Dispose() 
    { 
     if (this.Transaction != null) 
     { 
      (this.Transaction as IDisposable).Dispose(); // this is NHibernate ITransaction object 
       this.Transaction = null; 
     } 
     } 

}私はリポジトリパターンのオープンソース実装でそのコードスニペットを何度も見てきました

と私が見えることはできませんキャストの背後にある理由を理解する。直接transaction.Dispose()の場合は、をうまく動作させる必要があります。私は何か見落としてますか?

元のコードはここで見つけることができる: NHibernateTransaction.cs

+6

これは間違っています。 nullを割り当てることも間違っています。そうでなければ誤動作することはありません。誰もが本当に.NETをよく理解していないと書いています。 –

+0

これはあなたの答えです。http://stackoverflow.com/questions/4695649/cast-type-to-idisposable-why –

+1

@ハンス:どちらも_不必要です。あなたはそれを間違ったスタイルと呼ぶことができますが、実際には有害ではありません。しかし、「.NETを本当に理解していない」と合意しました。 –

答えて

3

IDisposableからITransaction継承ので、実装は、キャストが実装にアクセスするために必要とされる場合にexplicit interface implementationとしてIDisposableを実施していることが可能ですメンバー。

このような場合、キャストにより、コールがIDisposable.Disposeメソッドを呼び出すことが保証されます。キャストはすべての基盤をカバーするために行われます。

ITransactionIDisposableを継承しませんが、実装者が行う場合は、Disposeを呼び出し可能にするためにキャストが必要です。実装者がIDisposableを実装していない場合、そのようなケースは失敗する(例外をスローする)可能性があります。

+1

しかし、「ITransaction:IDisposable」が出発点です。 –

+1

@Henk - 私はすべての基底をカバーしようとしていました... – Oded

+1

@OdedトランザクションがIDisposableから継承しないと、.Dispose()が呼び出されたときにNull例外をスローします。だからまだ間違っている。私はそれが正しく貼り付けられたかどうか疑問に思います。 –

0

IDisposableから派生したインタフェースでDipose()を呼び出すと、違いはありません。

Dispose()が明示的に実装される可能性があるので、Dispose()IDisposableを実装するクラスで呼び出すときに違いが生じる可能性があります。

0

私はこれを頻繁にはしませんが、私はOdedが今言おうとしていることを理解しているので、私は元の答え全体を叩きました。この問題を解決することを目的としています。

namespace StackOverflow7051864 
{ 
    using System; 

    public interface ITransaction : IDisposable {} 

    public interface ITryToConfuseDispose 
    { 
     void Dispose(); 
    } 

    public class Transaction : ITransaction, ITryToConfuseDispose 
    { 
     void IDisposable.Dispose() 
     { 
      Console.WriteLine("Happy"); 
     } 

     void ITryToConfuseDispose.Dispose() 
     { 
      Console.WriteLine("Confused"); 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      EndTransaction(new Transaction()); 
     } 

     public static void EndTransaction(ITransaction transaction) 
     { 
      (transaction as IDisposable).Dispose(); 

      transaction.Dispose();    
     } 
    } 
} 

「transaction.Dispose()」は何を呼び出すのですか?それは呼び出すIDisposable.Dispose()

しかし、問題は、EndTransactionへの契約はITransactionなので、常にIDisposableバージョンを起動します。

+0

'ITransaction'が独自の' Dispose'メソッドを定義するとどうなりますか? – Oded

+1

@Oded、ITransactionには独自のDisposeメソッドがありません。 Dispose()メソッドは具象クラス(例えばNHibernateTransaction)で実装されています。まもなく私の元の質問に関連コードを追加します。 –

+1

@Oded実際には問題を引き起こすだろうが、私はあなたが依然としてIDisposableにキャストしてDispose()を呼び出すべきではないと主張するだろう。 ITransactionの実装者は、Dispose()メソッドで 'new'キーワードを使用する必要がありました。つまり、別のDispose()が呼び出されることを明示していました。私はこれが実用的で安全な現実世界のシナリオを与えることはこの質問に大いに役立つだろうと思います。 –

関連する問題