2012-03-06 4 views
2

誰かがC#でusingステートメントのように機能するメカニズムを実装する方法を考えることができるのだろうかと思っていましたが、より洗練された構文です。C#のステートメントを使用してオブジェクトを自動的に処理する別の構文はありますか?

C++/CLRでは、

MyClass NewObject; 

MyClassがここにマネージクラスで書くことができます。変数が範囲外になるとすぐにDisposeが呼び出されます。本質的には、同じことをC#usingと同じですが、より良い方法で行います。代わりに

using (MyClass NewObject1=new MyClass()) 
{ 
    xxxx; 
    using (MyClass NewObject2=new MyClass() 
    { 
    } 
} 

(私はこれは非常にきれいに見えない、それはすべての新しい変数のための新しいブロックを開くためにも退屈だと思う)

を書くの私はこのようなものを好むので

、 :

autodispose MyClass NewObject1=new MyClass(); 
xxxx; 
autodispose MyClass NewObject2=new MyClass(); 

誰もこのようなものを実装することは可能でしょうか? AOPやコード契約のフレームワークはコードを挿入するメカニズムを使用しているようですが、どうやってそれを行うのかはわかりません。

+2

'using'はまだ代替(' try'/'finally'、blech)よりもクリーンです –

+1

' MyClass'が 'IDisposable'を実装していない管理クラスの場合はどうなりますか? – phoog

+1

あなたはあなたの好みで(少なくともさらに装飾をしなくても)失う「使用する」というスコープを手に入れます。 –

答えて

6

ここでMyClassは管理対象クラスです。変数が有効範​​囲外になるとすぐにDisposeが呼び出されます。

これは、C++/CLRでもそうではありません。私の理解は、C++/CLRは従来のC++デストラクタセマンティクスではなく、マネージオブジェクトのコア.Netガベージコレクタに依然として依存しています...そして、これらのルールによって、オブジェクトは将来、ある種の非決定的なポイントに配置されます。それはかもしれない即刻...しかし、そうでない可能性があります。 おそらくとなります...しかし、あなたは確信が持てません。

C#の世界でさえ、usingブロックは、の管理対象外リソース(つまり、RAM以外のもの)用に予約されています。使用ブロックにオブジェクトを配置する必要はありません。ほとんどのものは安全に作成することができます。使用しているブロックが必要なときには、ネットワーク接続、データベース接続、ファイルハンドル、gdiリソース、システムタイマーなど、作成しているタイプにラップされているものがあります。

+0

私はC++/CLRと話すことはできませんが、オブジェクトの_destructor_をスコープから外れたときに一貫して呼び出すことは、少なくとも優れていると思います。 –

+0

@Joelこれは当てはまりません。 C++/CLIでは、スタックセマンティクスでヒープ管理オブジェクトを扱うことができます。これは本当に「統語的な砂糖や柄の柄」です。要約すると、ヒープに割り当てられたオブジェクトは、遅延ガベージコレクションではなく、ブロックの最後ですぐに削除され、その結果、デストラクタは削除時に直ちに呼び出されます。 Hogensonの引用_ C++/CLI_Foundations – Tod

+0

管理対象オブジェクトの 'Dispose'メソッドはオブジェクトを破壊しません。オブジェクトが意味的に役に立たなくなる可能性があり、オブジェクト(ファイナライズキューを含む)への外部参照を破壊する可能性がありますが、オブジェクトによって使用されるメモリは、次のGCサイクルまでは再利用されません。 – supercat

3

あなたは簡潔さを入力するためのあなたのusingステートメントを圧縮したい場合は、なぜそれはあなたが後にしているものですようですので、あなたはあなたの自己いくつかの中括弧といくつかの余分な行を保存することができます

using (MyClass class1 = new MyClass()) 
using (MyClass class2 = new MyClass()) 
using (MyClass class3 = new MyClass()) { 
    object xxxx; 
    // do some stuff 
} 

をしないで、それは重要ではない。あなたがところで簡潔-OCD

using (var class1 = new MyClass()) 
using (var class2 = new MyClass()) 
using (var class3 = new MyClass()) { 
    object xxxx; 
    // do some stuff 
} 

している場合は、usingは、C#のために良いことです。変数のスコープを定義すると、その変数のスコープが何であるか、いつ終了するのかが正確に分かります。そうでなければ、スコープは他の関数にも拡張することができます(例えば、関数への参照やそれを参照する別のオブジェクトへの参照を渡すなど)。

+0

私はまだ文の構文を使うのが好きではありません。私が望むなら、中括弧で変数の範囲を制御することができますが、私はそうする必要はありません。 – maxxxx

+0

C#を使用すると、C#の構造内に居住します。 C#の構造があなたの要件を満たしていない場合、多分あなたの仕事のための適切な言語ではありません。これは本当にあなたの個人的な好みに頼るので、これは本当にSOの建設的な質問ではありません。 –

+0

私は同意しません。私はそれが良い質問だと思う。私がC++について気に入っていることの1つは、常に成長しており、段階的に変化していることです。他の言語から良いコンセプトを借りれば、LINQをどうやって得ることができますか?この特定のトピックは、最終的には、構文上の粉末砂糖を軽く粉々にするだけではなく、スタックとヒープのセマンティクスの概念を考え、C#をより有用に(またはそうでない)全体を使用/処分することは、私に壊れたGCの約束のように感じます。 – Tod

5

私は答えがありませんが、私はそれをコメントとしてではなく答えとして書く価値があると感じています。私が間違って知っている限り、最も多くの票を持つ現在の回答があります。 Gordon Hogensonによると、の基盤C++/CLIは、 "構文的な砂糖や柄のハンドル"をサポートしています....要約すると、ヒープ割り当てされたオブジェクトはで、ブロックの最後にはすぐに削除されますその結果、デストラクタは削除直後に呼び出されます。 "ヒープセマンティクス

C++プログラマ(事前スマートポインタ)対-emphasis鉱山、P 63 スタックはすべて、彼らが新しい彼らはを削除しなければならないという事実のために使用されています。ただし、C++プログラマがローカル変数を作成するときに、ヒープに配置する必要はありません。スタックセマンティクスを使用することができ、オブジェクトを明示的に削除する必要はありません。 C++/CLIで

void Class::SomeMethod() 
{ 
    DbConnection connection; //No memory leak if not deleted 
    DbConnection leaky_connection = new DbConnection(); //on the heap will leak if not deleted 
} 

それは、ヒープ割り当てのために少し違って見えるでしょう:

DbConnection^ connection = gcnew DbConnection(); 

をしかし、MSは、C++プログラマは、彼らがスタックセマンティックバージョン許可セマンティクス積み重ねるために使用されて知っていたので、:

DbConnection connection; 

の存在を仮定:

~DbConnection() 
{ 
    //Close the connection 
} 
を10

スタックセマンティックバージョンは、接続が使用されているメソッドの最後でデストラクタをすぐに呼び出します。

私はこれをC#で行うことの難しさは、C++/CLIで許可されている理由とは反対のものだと思います(そして、ここでは問題になるかもしれません)。 C#のプログラマは、ガベージコレクタに処理を任せています。ローカルオブジェクトを非ローカルコンテナにスティックし、メソッドの終わりにスコープから外れる心配はありません。 GCはそれがコレクション内にあることを知っており、途中で破棄されることはありません。 C#は常にオブジェクト参照を扱い、ヒープとスタックのストレージを明示的に指定しません。 C#でこの "ハンドルの柄"を実装すると、おそらく多くのコードと期待が崩れます。

実際にはステートメント構文を使用しても、C#で予期しない問題が発生する可能性があります。私はこれのお気に入りの例をWhen Dispose Throws the Baby Out with the Bathwaterに書いていました。

+0

トッド、これを書いてくれてありがとう、私ができるよりもはるかに簡潔に。個人的には、私がやろうとしていることは、「使用する」ことを使用すること以上に問題を引き起こすとは思わない。異なる構文の場合と同じ動作です。私は意図的に、C++のスタック構文をコピーすることを提案していませんでした。いくつかのフレームワークがコードを挿入する方法を詳しく見ていく必要があります。たぶん私は何かを把握することができます。 – maxxxx

+0

「C#プログラマーはGCが物事を処理するのに慣れています」という難しさに関して、あなたは正しいですが、大きな問題があります。 GC管理のヒープは、通常の 'malloc'スタイルのヒープよりはるかに高速です*オブジェクトにはデストラクタやファイナライザがない場合に限ります。GCは、多数のオブジェクトを一度に解放できるときに最も効率的です。オブジェクトが破棄されるたびに少しのコードを実行する必要がある場合は、このようなことは起こりません。 GC管理のヒープと確定的なヒープの両方をサポートするためには、ランタイムは** 2つのヒープ**を維持する必要があり、複雑さとメモリオーバーヘッドが増えます。 –

+0

私の元の質問は、実際の動作を変更せずにusingステートメントの構文が異なることを忘れないでください。同じことがC++/CLIにも当てはまります。 "スタックのような"セマンティックは(私の目には)より良い構文ですが、C#の構文を使用するのとまったく同じです。 – maxxxx

関連する問題