C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

ログ内検索
  • キーワードを複数指定する場合は 半角スペース で区切ってください。
  • 検索条件は、(AND)=[A かつ B] (OR)=[A または B] となっています。
  • [返信]をクリックすると返信ページへ移動します。
キーワード/ 検索条件 /
検索範囲/ 強調表示/ ON (自動リンクOFF)
結果表示件数/ 記事No検索/ ON
大文字と小文字を区別する

No.77096 の関連記事表示

<< 0 >>
■77096  IDisposableの実装について
□投稿者/ 日曜プログラマー -(2015/09/10(Thu) 23:44:50)

    分類:[VB.NET/VB2005 以降] 

    2015/09/11(Fri) 00:08:11 編集(投稿者)
    2015/09/11(Fri) 00:05:29 編集(投稿者)

    いつもお世話になっております。

    IDisposableの使用方法について質問です。

    例えば、コンボボックスの更新時にBeginupdate・Endupdateを使用する際に
    Endupdateが必ず実行されるようにTry-Finallyで実装することがあると思います。
    でも、わざわざTry-Finallyを書くよりもusingで実装できたほうが楽だと考え、下記のようなサンプルクラスを作成しました。
    ただIDisposableはリソースを開放するためのインターフェイスだと理解していますが、
    今回のサンプルや追々実装したい内容ではリソースの開放は行いません。

    これは例で、他にもDB上のデータのロック・アンロックなどDispose内でクエリを実行するようなのも実装したいと考えています。

    変な質問ですが、この実装はアリですか?ナシですか?
    理由やそういう結論に達する考え方も教えてほしいです。
    また、他に楽に書ける方法などあればご教授いただきたいです。

    よろしくお願いいたします。

    'サンプルクラス
    Public Class Sample
    Implements IDisposable

    Private _target As ComboBox
    Public Sub New(ByVal target As ComboBox)
    Me._target = target
    End Sub

    Public Sub Update()
    Me._target.BeginUpdate()
    End Sub

    Private disposedValue As Boolean ' 重複する呼び出しを検出するには

    Protected Overridable Sub Dispose(disposing As Boolean)
    If Not disposedValue Then
    If disposing Then
    End If
    If Me._target IsNot Nothing Then
    Me._target.EndUpdate()
    End If

    End If
    disposedValue = True
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
    Dispose(True)
    End Sub
    End Class
親記事 /過去ログ130より / 関連記事表示
削除チェック/

■77097  Re[1]: IDisposableの実装について
□投稿者/ 魔界の仮面弁士 -(2015/09/11(Fri) 01:54:45)
    2015/09/11(Fri) 10:37:13 編集(投稿者)
    2015/09/11(Fri) 10:22:29 編集(投稿者)
    2015/09/11(Fri) 10:06:44 編集(投稿者)

    No77096 (日曜プログラマー さん) に返信
    > ただIDisposableはリソースを開放するためのインターフェイスだと理解していますが、
    > 今回のサンプルや追々実装したい内容ではリソースの開放は行いません。

    このインターフェイスの説明は、こう書かれていますね。

    .NET 1.1、2.0、3.0:
    『割り当てられたアンマネージ リソースを解放するメソッドを定義します。』

    .NET 3.5、4
    『割り当てられたリソースを解放するメソッドを定義します。』
    『このインターフェイスは主に、アンマネージ リソースを解放するために使用します。』

    .NET 4.5、4.6
    『アンマネージ リソースを解放するためのメカニズムを提供します。』
    『このインターフェイスは主に、アンマネージ リソースを解放するために使用します。』


    リソースの解放(≠開放)のために使われる事が多いですが、
    実際には何も解放しないというクラス実装になっている例もあります。

    また、今回やりたいことは、データベース処理における
    TransactionScope クラスのような物なのだと思いますし、
    手順的には問題無いものだと思います。


    ただ、Dispose という語からは「処分する」動作がイメージされますので、
    それが不自然に感じないようにする工夫は必要かと思います。


    たとえば StreamReader/StreamWriter の場合、Dispose された場合には、
    内包される BaseStream も巻き込んで処分されるようになっていますよね。

    ゆえに Reader/Writer の場合には、IDisposable でありながらも
    意図的に Dispose しない場合も多々あるわけで。


    それを考えると、利用者側の立場からすれば
     Using New Sample(ComboBox1)
    が行われたあと、Dispsoe 時に ComboBox を巻き込んで処分されるのでは
    無いだろうかという不安さ・不自然さを感じてしまいました。


    もちろん、クラスの実装者側からすれば、ComboBox が Dispose されないことは
    明確なのですが、それがクラスの利用者側に伝わるかは別の問題ですよね。

    クラス名に拘るとか、ドキュメント/XML コメントなどで明記ししておくなどの
    気遣いは必要かも知れません。

    ――そのための具体例となると、あまり良い例が思いつかないのですが、
    クラス名に何らかの統一ルールを決めておくのは如何でしょうか。

    たとえば TransactionScope を真似て、
    ComboBoxUpdateScope クラスとか、DataLockScope(Of T) クラスなど、
    何某 Scope といった命名規約で統一しておくとか。



    それと「Using ブロック」を使う前提だという事は、その呼び出し処理の
    開始と完了は、単一のメソッド内で完了するわけですよね。

    たとえば、Button1_Click にて BeginUpdate して
    Timer1_Tick にて EndUpdate される…といった、
    複数のメソッドにまたがる処理では無い、と。


    だとすれば、利用者側で Using を強制するよりは、Azulean さんが
    書かれたように、Using 内で行わせようとしていた処理そのものを、
    AddressOf なりラムダ式なりで渡す方が良いかもしれません。

    ajax のメソッドチェーンや、.NET の Task クラスなども、
    処理内容を匿名メソッド等で渡せるようになっていますね。
記事No.77096 のレス /過去ログ130より / 関連記事表示
削除チェック/

■77098  Re[1]: IDisposableの実装について
□投稿者/ Azulean -(2015/09/11(Fri) 07:14:45)
    2015/09/11(Fri) 07:39:16 編集(投稿者)

    No77096 (日曜プログラマー さん) に返信
    > ただIDisposableはリソースを開放するためのインターフェイスだと理解していますが、
    > 今回のサンプルや追々実装したい内容ではリソースの開放は行いません。

    本来の意図・理想を重視するとその通りです。
    それに反することに違和感を覚える方もいらっしゃるので、そのチーム次第かと思います。

    > 変な質問ですが、この実装はアリですか?ナシですか?
    > 理由やそういう結論に達する考え方も教えてほしいです。
    > また、他に楽に書ける方法などあればご教授いただきたいです。

    私は「あり」だと考えています。
    try-finally を重ねていくとインデントが深くなる、実装ミスのリスクが増えるので、かんたんに書ける using スコープを使うテクニックの方を推しています。

    実際、Rx(Reactive Extentions) には「Dispose が呼ばれたら任意の Action を実行する」オブジェクトを作ることができる、Disposable.Create というメソッドもあるので、
    そういった文化もあると考えています。
    https://msdn.microsoft.com/en-us/library/system.reactive.disposables.disposable.create



    あとは、BeginUpdate, EndUpdate, Try-Finally を書いたユーティリティメソッドを用意しておいて、そいつに更新用のアクションを渡すことでしょうか。
    C# で申し訳ないですが、イメージとして。

    void InUpdateAction(ComboBox combo, Action action)
    {
    combo.BeginUpdate();
    try
    {
    action();
    }
    finally
    {
    combo.EndUpdate();
    }
    }

    // 例
    InUpdateAction(_comboTest, () => { _comboTest.Items.Clear(); /* BeginUpdate と EndUpdate の間にやりたい処理を詰める */ });
記事No.77096 のレス /過去ログ130より / 関連記事表示
削除チェック/

■77099  Re[1]: IDisposableの実装について
□投稿者/ 魔界の仮面弁士 -(2015/09/11(Fri) 10:43:04)
    2015/09/11(Fri) 14:01:36 編集(投稿者)

    No77096 (日曜プログラマー さん) に返信
    > Public Class Sample
    >  Implements IDisposable
    >  Public Sub New(ByVal target As ComboBox)

    試しに ListBox 版を作って実験してみました。

    <削除>ListBox2 は高速化したけど、ListBox3 / ListBox4 は高速化しなかった…。</削除>


    <追記>
    →ごめんなさい! 私の勘違いでした。

    BeginUpdate が、コンストラクタの中で
      Me._target = target
      Me._target.BeginUpdate()
    と同時に呼ばれているのだと思い違いをしていましたが、
    提示頂いたコードでは、Update メソッドを明示的に呼ばないと
    BeginUpdate されない実装になっていたのですね。
    </追記>




     For n = 1 To 10000
      ListBox1.Items.Add(n)
     Next


     ListBox2.BeginUpdate()
     For n = 1 To 10000
      ListBox2.Items.Add(n)
     Next
     ListBox2.EndUpdate()


     Using x As New Sample(ListBox3)
      x.Update()  '追記:これを呼ばないと BeginUpdate されない
      For n = 1 To 10000
       ListBox3.Items.Add(n)
      Next
     End Using


     Using x = ListBox4.CreateUpdateBlock() 'Sample を Return する匿名メソッド
      x.Update()  '追記:これを呼ばないと BeginUpdate されない
      For n = 1 To 10000
       ListBox4.Items.Add(n)
      Next
     End Using
記事No.77096 のレス /過去ログ130より / 関連記事表示
削除チェック/

■77100  Re[2]: IDisposableの実装について
□投稿者/ ぶなっぷ -(2015/09/11(Fri) 12:49:48)
    個人的には、
    C++時代はデストラクタを何でも後始末メソッドとして使ってました。

    当時の私はデストラクタこそ、C++の最大の武器だと思っていました。
    Listの派生クラスを作って、そのデストラクタで全要素を削除する。

    とにかく全てのクラスはnewしたらそのリストにAddする。
    で、リストの寿命をその要素が必要な期間に合わせておく。
    で、疑似ガベージコレクタとか言ってました(笑)

    なので、その延長で考えるなら、IDisposableで「何でも後始末」は賛成
    と言いたいところですが、問題はC++のデストラクタは完全自動実行です
    が、IDisposableはusingしなきゃ実行されないこと。

    人はusingはリソースの後始末だと思ってるので、
    「リソースの後始末がなきゃよばなくていいんじゃね?」
    と思われてしまったら、呼んでもらえないと言うこと。

    そののあたりのジレンマとどう闘うかですね(^^;)
記事No.77096 のレス /過去ログ130より / 関連記事表示
削除チェック/

■77115  Re[3]: IDisposableの実装について
□投稿者/ Jitta -(2015/09/14(Mon) 20:28:14)
    No77100 (ぶなっぷ さん) に返信

    > なので、その延長で考えるなら、IDisposableで「何でも後始末」は賛成
    > と言いたいところですが、問題はC++のデストラクタは完全自動実行です
    > が、IDisposableはusingしなきゃ実行されないこと。
    >
    > 人はusingはリソースの後始末だと思ってるので、
    > 「リソースの後始末がなきゃよばなくていいんじゃね?」
    > と思われてしまったら、呼んでもらえないと言うこと。
    >
    > そののあたりのジレンマとどう闘うかですね(^^;)

    「後始末が必要なクラスである」ことを通知するのが、IDisposable インターフェイスを実装することかと。
    つまり、「リソースの後始末がなきゃ呼ばなくてもいいんじゃね?」ではなく、
    「リソースの後始末が必要だから IDisposable を実装する」
    「IDisposable を実装しているから、インスタンスが必要なくなったら Dispose する」
    じゃないかと。

     Windows Form の Control クラスは、インスタンス化しただけではリソースの確保を行っていません。
    表示して初めてリソースの確保を行い、Dispose が必要になります。
    Form クラスは、Show/Close の組み合わせなら Dispose も行います。しかし、ShowDialog では Dispose を呼ばなければなりません。
    そんなことは関係なく、「IDisposable を実装しているから、必要なくなったら Dispose する」。
記事No.77096 のレス / END /過去ログ130より / 関連記事表示
削除チェック/

■77104  Re[1]: IDisposableの実装について
□投稿者/ WebSurfer -(2015/09/12(Sat) 12:28:57)
    No77096 (日曜プログラマー さん) に返信

    全くの個人的意見で質問者さんには当てはまらないかもしれませんが・・・

    > この実装はアリですか?ナシですか?

    「ナシ」だと思います。理由は、ルールを作ってドキュメント化し、組
    織的にシステマチックに強制的に実施しないと忘れるからです。

    質問者さんのハンドル名からの想像ですが、個人でプログラムを作って
    おられるのではないかと思います。

    そうであれば「ルールを作ってドキュメント化し・・・」というところ
    はどうなんでしょう?

    自分は趣味のサンデープログラマーなんですが、いろいろと忘れてしま
    って、昔作ったプログラムを修正するような場合に苦労しています。ま
    して、特別なことをすると、保守不能になるかもしれません。(笑)

    質問者さんの場合は問題ないということでしたら失礼しました。



    以下、質問とは直接関係ないことですが・・・

    Dispose は不要と言っているわけではないです。

    逆に、IDisposable を継承するクラスは Dispose を呼ぶべきというのが
    基本だと思っています。

    以下の MSDN ライブラリによると、"マネージリソースのみを使用する型は、
    ガベージコレクターによって自動的にクリアされるため、このような型で
    Dispose メソッドを実装しても、パフォーマンス上の利点はありません。"
    とのことです。(.NET 4.6 / 4.5 の記事にはその説明はありませんが同じ
    ことかと思います)

    Dispose メソッドの実装
    https://msdn.microsoft.com/ja-jp/library/vstudio/fs2xkftw(v=vs.100).aspx

    しかし、Dispose メソッドには、メモリ開放の機能以外に、GC.SuppressFinalize
    メソッドを実装することにより、冗長なファイナライザーの呼び出しを防ぐこ
    とができるそうです。上に紹介した「Dispose メソッドの実装」にもそのこと
    が書いてあります。

    クラスによってはコンストラクタに GC.SuppressFinalize メソッドが実装さ
    れており、冗長な Finalize メソッドの呼び出しを防ぐという意味では
    Dispose メソッドを呼ぶ必要はないものもあります。

    ただし、コンストラクタでの GC.SuppressFinalize の実装は MSDN ライブラ
    リなどにはドキュメント化されてない(ソースコードを見ないと分からない)、
    ソースコードは変更される可能性がある、将来ネイティブリソースが含まれる
    可能性はゼロではない・・・ということを考えると、やはりDispose は呼んだ
    方がよさそうです。
記事No.77096 のレス /過去ログ130より / 関連記事表示
削除チェック/

■77105  Re[2]: IDisposableの実装について
□投稿者/ 日曜プログラマー -(2015/09/12(Sat) 13:55:38)
    ご返信ありがとうございます。

    皆様のご意見、大変参考になりました。

    確かに決まりきった実装以外を匿名メソッドにしておけば
    プログラマーは内部の実装だけを気にしておけばよいですね。

    毎度Try-Finallyを記述するのが面倒だったので、
    今回のご返信内容を参考にして解消できそうです。

    ありがとうございました。
記事No.77096 のレス / END /過去ログ130より / 関連記事表示
削除チェック/

■77116  Re[3]: IDisposableの実装について
□投稿者/ なちゃ -(2015/09/15(Tue) 03:09:34)
    昔と違って標準ライブラリなどでも平気でリソース解放ではなくいわゆるコンテキストやスコープ生成的な目的でIDisposableを使うようになっているので、目的が明確になっていれば使えばいいと思いますよ。
    クラスのドキュメントコメントに明記しとけば忘れる心配はありません。
    ※もちろんきちんと実装する前提ですが

    個人的には例えばMarshalByValueComponentなんてのはDispose呼ぶ必要なんてないと思いますけどね。
    これにネイティブリソースが追加されたりDispose呼ばないとリソース解放漏れが発生するように実装が変えられるなんてありえないので。
    例えばDataSetとかなんてそうです。
    勝手にシリアライズされて管理外に飛んでったりするものを、確実にDisposeするなんて不可能ですし無意味なのは自明なので。
記事No.77096 のレス / END /過去ログ130より / 関連記事表示
削除チェック/



<< 0 >>

パスワード/

- Child Tree -