27

インターフェイスの1つをIDisposableで拡張するか、インターフェイスを実装するクラスにIDisposableを実装するかをどのように判断できますか?

1つの特定の実装を除いて、外部リソースを破棄する必要のないインターフェイスがあります。私の選択肢は次のようです:

1)空のメソッドのみであっても、Disposeを実装するためにすべての実装を必要とするインターフェースにIDisposableを実装します。

-また-

2)IDisposableを、破棄する必要のあるリソースを持つクラスにのみ実装します。私のオブジェクトはファクトリから作成されているため、すべてのアップストリームコードがインターフェイスに対して機能するため、これにより「使用」で問題が発生します。インターフェイスはIDisposableにバインドされていないため、「using」はDisposeメソッドを認識しません。ただし、ファクトリの結果を実装にキャストすることはできます。しかし、それは消費者に実装を認識させ、インターフェースの目的を無効にします。

ベストプラクティスに関するアイデアはありますか?

4

3 に答える 3

19

呼び出し元がインターフェースとしか対話できず、実装とは対話できないと予想される場合は、インターフェースを extends したいと考えていますIDisposable。そうでない場合は、破棄する必要があるかどうかを確認する必要がありvalue is IDisposableます。

オブジェクトの破棄を担当するオブジェクトが具体的な実装を認識しており、インターフェイスを使用するのは、それへの参照が与えられている (ただし、破棄の責任を負わない) オブジェクトだけである場合は、2 番目のオプションを検討してください。

最初のオプションの良い例はIEnumerator. 多くのIEnumeratorオブジェクトは、破棄されたときに何もする必要はありませんが、一部のオブジェクトは破棄されIDisposableます。そのため、そのオブジェクトの作成/ライフサイクルを担当するオブジェクトは、基になる実装についての知識を持たない (または持つべきではない) ため、インターフェイスが拡張されます。

2 番目の例は、比較する必要があるIComparer 多くのオブジェクトが使い捨てであるようなものですが、インターフェースを介してオブジェクトを使用するコードのセクションは、オブジェクトの作成/ライフサイクルに責任がないため、タイプは使い捨てです。

于 2013-01-16T22:07:21.100 に答える
10

50,000 ドルの問題は、破棄の責任がインターフェイスと共に引き継がれるかどうか、または別の言い方をすれば、実装オブジェクトを使用する最後のエンティティが、それを作成したエンティティ以外のものである可能性があるかどうかです。

実装する大きな理由は、IEnumerator<T>実装IDisposableオブジェクトは実装するオブジェクトによって作成されますIEnumerable<T>.GetEnumerator()が、通常は他のオブジェクトによって使用されるためです。実装するオブジェクトはIEnumerable<T>、返されたものを本当に破棄する必要があるかどうかを認識しますが、受信者がそれをいつ処理したかを知る方法はありません。呼び出したコードはIEnumerable<T>.GetEnumerator()、返されたオブジェクトの処理がいつ完了したかを認識しますが、クリーンアップが必要かどうかを知る方法はありません。賢明なことはIEnumerable<T>.GetEnumerator()、返されたオブジェクトDisposeが放棄される前にそのオブジェクトを呼び出すことを保証するために、呼び出すコードが必要であることを指定することです。のDisposeメソッドは多くの場合何もしませんが、存在することが保証されている何もしないメソッドを無条件に呼び出す方が、存在しないメソッドの存在をチェックするよりも安価です。

インターフェイス タイプの性質が、実装オブジェクトのクリーンアップが必要かどうか、およびそのようなクリーンアップがいつ発生するかという問題の両方が同じエンティティによって回答されるようなものである場合、インターフェイスが継承する必要はありませんIDisposable。インスタンスが 1 つのエンティティによって作成され、最後に別のエンティティによって使用される場合は、継承IDisposableが賢明です。

于 2013-01-18T00:20:29.833 に答える
4

具象クラスとインターフェイスに実装する場合IDisposable、ユーザーはそれが使い捨てである可能性があることを知っています。できるよ

IFoo foo = Factory.Create("type");
using(foo as IDisposable){
    foo.bar();
}

fooが実装されていない場合IDisposableusing意志はusing(null)うまく機能します。

以下のサンプルプログラムの出力は、

Fizz.Bar
Fizz.Dispose
Buzz.Bar

サンプルプログラム

using System;

internal interface IFoo
{
    void Bar();
}
internal class Fizz : IFoo, IDisposable
{
    public void Dispose()
    {
        Console.WriteLine("Fizz.Dispose");
    }

    public void Bar()
    {
        Console.WriteLine("Fizz.Bar");
    }
}
internal class Buzz : IFoo
{
    public void Bar()
    {
        Console.WriteLine("Buzz.Bar");
    }
}

internal static class Factory
{
    public static IFoo Create(string type)
    {
        switch (type)
        {
            case "fizz":
                return new Fizz();
            case "buzz":
                return new Buzz();
        }
        return null;
    }
}

public class Program
{

    public static void Main(string[] args)
    {

        IFoo fizz = Factory.Create("fizz");
        IFoo buzz = Factory.Create("buzz");

        using (fizz as IDisposable)
        {
            fizz.Bar();
        }
        using (buzz as IDisposable)
        {
            buzz.Bar();
        }
        Console.ReadLine();
    }

}
于 2013-02-22T19:21:15.123 に答える