2009-07-07 21 views
19

C#には、特にIDisposableオブジェクト用のusingステートメントがあります。おそらく、usingステートメントで指定されたオブジェクトは、確定的に解放されるべき何らかの種類のリソースを保持するでしょう。悪い練習ですか?ステートメントを使用しているC#の非標準的な使用

しかし、私は、単一の明確な開始点と終了点を持つが、固有の言語サポートがないプログラミングには多くの設計があるように思えます。 using構成は、コードエディタの組み込み機能を使用して、そのような設計または動作の範囲を少なくとも明確かつ自然に強調する機会を提供する。

私が心に留めていることは、「開始」と「結合」を含む非同期コードの実行など、さまざまな種類がありますが、頻繁にBeginXXX()EndXXX()メソッドで始まる操作の種類です。

この簡単な例をご覧ください。

webDataOperation.Start(); 
GetContentFromHardDrive(); 
webDataOperation.Join(); 
// Perform operation that requires data from both sources 

何場合は、代わりに、Startメソッドは、そのIDisposable.Dispose方法結合操作を実行したオブジェクトが返されました。

using(webDataOperation.Start()) { 
    GetContentFromHardDrive(); 
} 
// Perform operation that requires data from both sources 

それとも、いっそ、私は、特に念頭に置いていた:私は専門性の高いグラフィックスは、ブリット行い、Begin()End()方法(また、DirectXの中に存在し、XNAデザイン)を持つオブジェクトを持っています。代わりに...

using(blitter.BlitOperation()) { 
    // Do work 
} 
// Use result 

より自然で読みやすいように見えますが、それが意図しない目的でIDisposableインタフェースとusing文を使用して見て、お勧めできませんか?換言すれば、これは、と直観的ではなく、直観的ではない方法でオペレータをペイロードするでしょうか

+0

最後に{最初と最後}を使用しないのはなぜですか?これは、悪用することなく範囲を提供します。 – cja

答えて

20

これは完全に許容される方法です。これは因数分解型と呼ばれ、Framework Design Guidelinesはこれを行うことを推奨します。

基本的に、型が特定の有効期間内に操作をラップする場合は、IDisposableとusingステートメントを使用して考慮する必要があります。

実際にはthis specific topic hereについてもブログしました。

+0

良い発見ですが、議論の理由がありますか?この記事では推奨していますが、理由は説明しません。 – snarf

+0

これは、EndOperation()が常にDispose()によって呼び出されることを保証するためです。 –

+1

@Snarfblam:基本的に、操作自体はクリーンアップを必要とするリソースとして機能します。詳細は私のブログ記事を読んでください - それは第2のリンクです。私はここよりもはるかに正当な理由があります。 –

2

私はIDisposableを何を意図しているのか、それ以外のものは使用しないといけないと思います。つまり、メンテナンス性があなたにとって重要であれば。

+1

John:因果関係型に関するフレームワーク設計ガイドラインを参照してください。http://blogs.msdn.com/brada/archive/2009/02/23/framework-design-guidelines-factored-types.aspx - これは現在推奨されていますそれらを扱うアプローチ。 –

+0

これは保守性にどのような影響を及ぼしますか?そしてこれがキヤノンに厳格な遵守を推奨する唯一の理由ですか? – snarf

+0

これは、他の開発者が何が起こっているのかを理解する能力に影響します。私の推薦理由は、IDisposableを通常の理由で使用するのは難しいということです。追加のものは必要ありません。 –

0

私は、実際には、特定のコードブロックの最後にトリガーされたアクションをいくつかのプロジェクトで使用しました。

ウェスDeyerはASCIIアートプログラムに彼のLINQでそれを使用して、彼は(ウェスは、C#コンパイラチームで動作します - 私は彼の判断を信頼したい:Dを):使い捨てアクションと呼ん

http://blogs.msdn.com/wesdyer/archive/2007/02/23/linq-to-ascii-art.aspx

class ActionDisposable: IDisposable 
{ 
    Action action; 

    public ActionDisposable(Action action) 
    { 
     this.action = action; 
    } 

    #region IDisposable Members 

    public void Dispose() 
    { 
     this.action(); 
    } 

    #endregion 
} 

は今、あなたは関数からということを戻し、このような何かを行うことができます。

using(ExtendedConsoleWriter.Indent()) 
{ 
    ExtendedConsoleWriter.Write("This is more indented"); 
} 

ExtendedConsoleWriter.Write("This is less indented"); 
+1

うわー、これはusingステートメントの暴力的な乱用です。 ExtendedConsoleWriterのコードを開くことなく、そのコードが何をしようとしているのか分かりません。コードの周りにIncreaseIndentとDecreaseIndentが呼び出された場合、疑問はありません。 –

+0

私はこれに "using"を使用しませんが、似たようなキーワードと "with"のような関連するインターフェースがあったとします:with(writer.Indent()){stuff; }、それは納得のいく構造です。 – snarf

+3

Yikes、Ryan。それはすばやく書かれた例だった。私は同意する、私はそれをIncreaseIndentと呼ぶだろう - その場合、私はそれを "usingステートメントの暴言的な乱用"と呼んでいないだろう。このようなコンセプトは、.NET全体のトランザクションをスコープする際に見ることができます。これは、ここで少し難解になっているようです。 – Charles

5

それは一般的なパターンですが、個人的に、私はIDを乱用するの言い訳はありませんと信じていますあなたが匿名の代理人やラムダを使って同じ効果をはるかに明白な方法で達成することができるときは、そういうものです。すなわち:

blitter.BlitOperation(delegate 
{ 
    // your code 
}); 
+0

そして、あなたが言いたいのは、常に別のスレッドで作業をしたいのであれば、コードを分解する必要はありません(つまり、この設計は価値を追加します)。 –

+0

私はこのパターンが好きですが、独自の複雑さ - 場合によっては、usingステートメントによる処理よりも明らかにならない場合があります。多くの(特にエントリレベルの)開発者はlambdasをgrokkingする問題を抱えています。 –

+0

これは、等価な安全性を考慮していない場合もあります。たとえば、yieldステートメントでメソッドの内部でこれを使用したり、クリーンアップを保証することはできません。 –

6

(フィル・ハークが、それは大丈夫だと言うのでまたは)あなたは、あなたがすべきという意味ではありませんすることができますという理由だけで。

基本的なルール:あなたのコードを読んで、それが何をしているのか、あなたの意図が何であるのかを理解できれば、それは受け入れられます。一方で、あなたが何をしたのか、なぜそれをしたのか説明する必要がある場合、おそらく中流の開発者がコードを管理しています。

カプセル化を強化してこれを実現できる他の多くのパターンがあります。

結論:この「テクニック」はあなたに何も買わず、他の開発者を混乱させます。

+0

+1を理解していただきありがとうございます。私は完全に同意しますが、一般的には、IDisposableをファクタ型に使用することは、多くの場合、非常にきれいで理解可能な手段を提供すると考えていますが、コードを正しく記述するだけでなく、あなたはやっている。つまり、BCLのTransactionScopeは私に自然です。ここでの別の回答のインデントコードはありません。多くの事のように、私はこれが助けになると思いますが、簡単に虐待される可能性があります。 –

+0

合意。何がうまくいくの?興味深いコンセプトで逃げ出すのは簡単ですが、実際の世界のプロジェクトでは、混乱させるだけのものは使用しないでください。 – Charles

+0

それは私に混乱しているように見えたなら、私は尋ねなかったでしょう。潜在的な混乱を無視して、より簡潔な代替案がありますか?私はインライン、インデント、言語サポートのどれが「使用する」のが好きで、明示的に、具体的かつ明示的にスコープをカプセル化しているのが好きです。 – snarf

12

私はそれに反対します。私の信念は、コードはコンパイラではなくコードのメンテナーと効果的にやりとりすることであり、メンテナーの理解を念頭に置いて書かなければならないということです。私は、リソース(通常は管理されていないリソース)を処分するためだけに "使用する"ことを試みます。

私は少数派です。ほとんどの人は一般的な目的として "using"を使用しているようです。 "例外がスローされてもクリーンアップコードを実行したい"という仕組みです。

(1)私たちはすでに「try-finally」と呼ばれるメカニズムを持っています。(2)意図しない目的のために機能を使用しています。クリーンアップコードは重要ですが、なぜそれが呼び出された時点でそれが見えないのですか?それが重要なら、私はそれを見ることができるようにしたい。

+0

「使用する」というこのテイクは無制限です。好奇心の念から、C#には、たとえそれが完全にはっきりと機能していても、その使用が推奨されていなかったため、C#では他の言語機能がありますか? –

+0

@KirkWoll:はい。私は彼らのために設計されたもの以外のものに使用されている*すべての*言語機能を使用することをお勧めします。 –

+0

@EricLippert - もちろん、言語機能が何のために設計されたのかは必ずしも明らかではありません。実際、「使用する」という特定のケースであっても、「使用している」という名前は、管理対象外のリソースを廃棄するためだけに使用されることはないと考えられていたため、 – kvb

関連する問題