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

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

C# と VB.NET の入門サイト

メモリリークに関して [1]

[トピック内 42 記事 (21 - 40 表示)]  << 0 | 1 | 2 >>

■91532 / inTopicNo.21)  Re[4]: メモリリークに関して
  
□投稿者/ kiku (107回)-(2019/07/04(Thu) 09:00:50)
No91529 (魔界の仮面弁士 さん) に返信
> 実際 CE においても、親 Form が Dispose されれば、その配下のコントロール群も
> Dispose されることを確認できました。
> とはいえ、子コントロールの Dispose が確実に呼ばれているのか、
> たまたま GC されただけなのかまでは分かりません。

子コントロールをすべて明示的にDisposeするように対応したいと思います。

> あと、経験則的なところで言えば、.NET Compact Framework 環境の場合、
> オブジェクトの使用後は、参照変数に Nothing 代入を積極的に行った方が良いみたいです。

引用されているURLも一通り読んでみました。
子コントロールにnullを設定するように対応したいと思います。
引用返信 編集キー/
■91533 / inTopicNo.22)  Re[7]: メモリリークに関して
□投稿者/ kiku (108回)-(2019/07/04(Thu) 09:08:37)
No91530 (魔界の仮面弁士 さん) に返信
> 一方 .NET Comapct Framwork の場合、ソースコードは提供されていませんが、
> No91525 の実験結果から、Form.Dispose(bool) は特に存在しておらず、
> 直接 Control.Dispose(bool) がそのまま呼ばれていることが確認できました。

だとすると、
子コントロールは明示的にDisposeしなくても良く、
子コントロールが保持するFontなどのアンマネージリソースのみをDisposeすれば良いのでしょうか?

> Nothing の代入有無で、本当に解放状況が変化するかどうかを確認してみました。
> 端末を再起動して、空きメモリが十分に確保されている状態において、
> Button1 でモードレス フォームを表示させた後、
> Button2 でそれを Close させています。
> すると、Close 直後の ★の行の Nothing 代入がコメントアウトされていた場合、
> Form2 および LabelEx が直ちに Dispose されないケースが確認できました。
> しかし Nothing 代入するようにした場合は、Button2 の時点ですぐに Dispose されるようになりました。
> ただ、何度も実験を繰り返すと空きメモリが減ってくるようで、
> その場合はどうやら GC が発動するらしく、Nothing 代入せずとも
> Dispose される結果になるようです。

そうすると、子コントロールは明示的にDisposeを行って、
子コントロールにnull(今回C#なため)を設定し、
子コントロールが保持するアンマネージリソースに対しても明示的にDisposeを行い、
その参照もnullに設定するのが良さそうと理解しました。

引用返信 編集キー/
■91534 / inTopicNo.23)  Re[7]: メモリリークに関して
□投稿者/ 魔界の仮面弁士 (2218回)-(2019/07/04(Thu) 09:13:04)
No91530 (魔界の仮面弁士) に追記
>>あと、経験則的なところで言えば、.NET Compact Framework 環境の場合、
>>オブジェクトの使用後は、参照変数に Nothing 代入を積極的に行った方が良いみたいです。
> Nothing の代入有無で、本当に解放状況が変化するかどうかを確認してみました。


すみません!
C# の質問に、うっかり VB で回答してたことに、今朝になって気がつきました。

# .NET 対応前、CE アプリを eVB3 で行ってきた期間が長すぎて、
# CE 環境だと反射的に VB で書く癖が…。orz


> 端末を再起動して、空きメモリが十分に確保されている状態において、
> Button1 でモードレス フォームを表示させた後、
> Button2 でそれを Close させています。
> すると、Close 直後の ★の行の Nothing 代入がコメントアウトされていた場合、
> Form2 および LabelEx が直ちに Dispose されないケースが確認できました。

上記の「Close 後、直ちに Dispose されていない」現象ですが、
改めて C# (CFx 3.5 SP1) でも実験してみたところ、上記の状況を再現させられませんでした。
Close されたら、null を代入せずとも即座に Dispose されているようにみえる…。


改めて、昨日の VB コードでも再検証してみましたが、
昨日と比べて問題の再現率が大幅に低下していました。
狙って再現させることは難しそうです。


public partial class Form1 : Form
{
  private Form2 f = null;
  public Form1()
  {
    InitializeComponent();
    DoubleClick += delegate { Close(); };
  }

  /// <summary>新規に Form2 を表示するコード</summary>
  private void button1_Click(object sender, EventArgs e)
  {
    f = new Form2();
    f.Show();
  }

  /// <summary>直前に表示された Form2 を閉じるコード</summary>
  private void button2_Click(object sender, EventArgs e)
  {
    if (f != null /* && !f.IsDisposed */)
    {
      f.Close();
      // f = null; // ★
    }
  }
}

// -=-=-=-=-=-=-=-=-=-=-=-=-

public partial class Form2 : Form
{
  private readonly Guid Id = Guid.Empty;
  public Form2()
  {
    Id = Guid.NewGuid();
    Trace.WriteLine(String.Format("==> {0} 生成 {1}", GetType().Name, Id));
    InitializeComponent();
    Controls.Add(new LabelEx());
    Text = Id.ToString();
    DoubleClick += delegate { Close(); };
    // Disposed += delegate { Trace.WriteLine(string.Format("<== {0} 破棄 {1}", GetType().Name, Id)); };
  }
  public sealed class LabelEx : Label
  {
    private readonly Guid Id;
    public LabelEx()
    {
      Id = Guid.NewGuid();
      Trace.WriteLine(String.Format("==> {0} 生成 {1}", GetType().Name, Id));
      Text = Id.ToString();
      //Disposed += delegate { Trace.WriteLine(string.Format("<== {0} 破棄 {1}", GetType().Name, Id)); };
    }
    protected override void Dispose(bool disposing)
    {
      Trace.WriteLine(string.Format("<== {0} 破棄 {1} ({2})", GetType().Name, Id, disposing));
      base.Dispose(disposing);
    }
  }
  protected override void Dispose(bool disposing)
  {
    Trace.WriteLine(string.Format("<== {0} 破棄 {1} ({2})", GetType().Name, Id, disposing));
    if (disposing && (components != null))
    {
      components.Dispose();
    }
    base.Dispose(disposing);
  }
}
引用返信 編集キー/
■91535 / inTopicNo.24)  Re[6]: メモリリークに関して
□投稿者/ kiku (109回)-(2019/07/04(Thu) 09:23:39)
No91531 (PANG2 さん) に返信
> ■No91523 (kiku さん) に返信
>>PANG2さんからご紹介頂いたWeakReferenceを使ってみたのですが、
>>うまく判断できないように見えました。
>
> WindowsとCEで差異はありますか?

デバック実行にて実行してみました。
差異はありませんでした。

1回目のメッセージボックス
 From1(a)(d)
 label1(a)(d)
 textBox1(a)(d)

2回目のメッセージボックス
 From1
 label1
 textBox1

引用返信 編集キー/
■91536 / inTopicNo.25)  Re[8]: メモリリークに関して
□投稿者/ kiku (110回)-(2019/07/04(Thu) 09:33:19)
No91534 (魔界の仮面弁士 さん) に返信
> すみません!
> C# の質問に、うっかり VB で回答してたことに、今朝になって気がつきました。

ぜんぜん大丈夫です。
VBでもC#でもそれほど大差ないですし。

> 上記の「Close 後、直ちに Dispose されていない」現象ですが、
> 改めて C# (CFx 3.5 SP1) でも実験してみたところ、上記の状況を再現させられませんでした。
> Close されたら、null を代入せずとも即座に Dispose されているようにみえる…。

なるほど、nullを代入せずとも良さそうということですね。
ご紹介頂いたnullを設定して効果があったという記事もありますし、
念のため、nullを代入してみるのも良いかも思いました。
引用返信 編集キー/
■91537 / inTopicNo.26)  Re[8]: メモリリークに関して
□投稿者/ 魔界の仮面弁士 (2219回)-(2019/07/04(Thu) 09:59:49)
No91533 (kiku さん) に返信
> 子コントロールは明示的にDisposeしなくても良く、
> 子コントロールが保持するFontなどのアンマネージリソースのみをDisposeすれば良いのでしょうか?

.NET Framework の場合、Control.Font プロパティは Ambient なので、手出しすべきではありません。
一つの Font インスタンスが、複数のコントロールで扱われる可能性があるためです。


.NET Compact Framework の場合は、正直分かりません。
各種処理が Microsoft.AGL.Forms 名前空間経由で、DllImport されてしまっていて、
処理内容を追跡できそうにありません。
Microsoft 有償サポートに問い合わせようにも、ライフサイクルが既に終了してしまっていますし。


以下、Font プロパティが返すインスタンスに関する実験コード。

var sb = new StringBuilder();
var f1 = textBox1.Font;
var f2 = f1;
textBox1.Font = f1;
var f3 = textBox1.Font;

sb.AppendLine("--等価判定の実装状況--");
sb.AppendLine(string.Format("f1==f2         :{0}", f1 == f2));
sb.AppendLine(string.Format("f1.Eq(f2)      :{0}", f1.Equals(f2)));
sb.AppendLine(string.Format("RefEq(f1, f2)  :{0}", ReferenceEquals(f1, f2)));
sb.AppendLine("--Fontプロパティ--");
sb.AppendLine(string.Format("f2==f3         :{0}", f2 == f3));
sb.AppendLine(string.Format("f2.Eq(f3)      :{0}", f2.Equals(f3)));
sb.AppendLine(string.Format("RefEq(f2, f3)  :{0}", ReferenceEquals(f2, f3)));

textBox1.Text = sb.ToString();
MessageBox.Show(sb.ToString());

====

【.NET Compact Framework 3.5 SP1】
--等価判定の実装状況--
f1==f2         :True
f1.Eq(f2)      :True
RefEq(f1, f2)  :True
--Fontプロパティ--
f2==f3         :False
f2.Eq(f3)      :True
RefEq(f2, f3)  :False


【.NET Framework 3.5 SP1】
--等価判定の実装状況--
f1==f2         :True
f1.Eq(f2)      :True
RefEq(f1, f2)  :True
--Fontプロパティ--
f2==f3         :True
f2.Eq(f3)      :True
RefEq(f2, f3)  :True

引用返信 編集キー/
■91538 / inTopicNo.27)  Re[9]: メモリリークに関して
□投稿者/ kiku (111回)-(2019/07/04(Thu) 10:46:45)
No91537 (魔界の仮面弁士 さん) に返信
> .NET Framework の場合、Control.Font プロパティは Ambient なので、手出しすべきではありません。
> 一つの Font インスタンスが、複数のコントロールで扱われる可能性があるためです。
> .NET Compact Framework の場合は、正直分かりません。
> 各種処理が Microsoft.AGL.Forms 名前空間経由で、DllImport されてしまっていて、
> 処理内容を追跡できそうにありません。
> Microsoft 有償サポートに問い合わせようにも、ライフサイクルが既に終了してしまっていますし。

AmbientとはフォームのFontを子コントロールが継承する機能であると理解しました。
よって、フォームのFontと子コントロールのFontは同じインスタンスである場合がある。
このような状況において、子コントロールのFontをDisposeしてしまうと、
フォームのFontがどうなっちゃうの?ってことであると理解しました。

フォームAのFontと、フォームBのFontが共用されることがなければ
フォームAのDisposeのタイミングで、フォームAの子コントールのFontを
Disposeするには、問題ないと考えても良いのでしょうか?
※よくわからないと記述があるので、わからないという回答かと思いますが(泣き)


> 以下、Font プロパティが返すインスタンスに関する実験コード。

この実験の結果をどのように理解していいか
正直に言いますと良くわかりませんでした。
FALSEになるってことは、textBox1.Font = f1;を実行したときに
f1が設定されるのではなく、フォームのFontから継承される機能が働き、
別のインスタンスになるのではという理解で現在はいます。

引用返信 編集キー/
■91539 / inTopicNo.28)  Re[10]: メモリリークに関して
□投稿者/ 魔界の仮面弁士 (2220回)-(2019/07/04(Thu) 12:11:33)
No91538 (kiku さん) に返信
> AmbientとはフォームのFontを子コントロールが継承する機能であると理解しました。
> よって、フォームのFontと子コントロールのFontは同じインスタンスである場合がある。

アンビエントの具体例として:

.NET Framework の場合、
デザイン画面で Form に Label を貼って、
その後で Form の Font を変更すると、
Label の Font も連動して変更されます。

このとき、デザイナのプロパティ グリッドを見てみると、
Form の Font プロパティは変更されて太字表示されていますが、
Label の Font は細字表示のままとなります。

Label の Font を意図的に変更すれば、Label の Font プロパティも
太字で表示されますが、この状態だと、Form の Font に連動しなくなります。


ところが、.NET Compact Framework の場合、上記の動作が実装されていませんので、
Compact Framework の実装がアンビエントになっている可能性は低いと予想しています。


> この実験の結果をどのように理解していいか
> 正直に言いますと良くわかりませんでした。

.NET Comapct Framework の Font プロパティの getter は、
アクセスするたびに、新しい Font インスタンスを
生成する実装になっている可能性が高いことが伺えます。

その根拠は、
 var f1 = textBox1.Font;
 var f2 = textBox1.Font;
において、f1 と f2 が別のインスタンスとなったという点からです。
(同じインスタンスを返す条件が存在する可能性を否定することは出来ませんが)


また、No91525 のコードで「get_Font」メソッドの実装状況を調べたところ、
Font プロパティは Control クラスで宣言されているのみで、
継承先(Label や Form や ContainerControl 等)でオーバーライドされていないこともわかります。


という事はすなわち、最初の No91509 にて記述されていた、

>> this.lbl_serialnumber.Font.Dispose();//★対策追加

というコードが無価値であるように思うのです。

Font プロパティにアクセスするたびに新しい Font が生成され、
それがすぐに破棄されるだけなのではないかと。
(メモリ負荷等は見ていないので、アンマネージリソースの管理状況までは分かりませんが)


では、そもそも破棄した Font を使おうとしたらどうなるのか?

var f1 = new Font(FontFamily.GenericMonospace, 12, FontStyle.Regular);
var f2 = new Font(FontFamily.GenericMonospace, 12, FontStyle.Regular);
f2.Dispose();
button1.Font = f1;
button2.Font = f2;
button1.Font.Dispose();



てっきり ObjectDisposedException が発生するのかと思いきや、そうでは無いようです。

.NET Compact Framework の場合は、button1 だけが新しいフォントになります。
button2 の方は以前のフォントのままレンダリングされていました。

一方 .NET Framework においては、button1 / button2 両方とも
新しいフォントでレンダリングされました。エラーになることもなく。
引用返信 編集キー/
■91540 / inTopicNo.29)  Re[11]: メモリリークに関して
□投稿者/ kiku (112回)-(2019/07/04(Thu) 13:13:14)
No91539 (魔界の仮面弁士 さん) に返信
> ところが、.NET Compact Framework の場合、上記の動作が実装されていませんので、
> Compact Framework の実装がアンビエントになっている可能性は低いと予想しています。

ありがとうございます。
アンビエントに関して良く理解できました。

> .NET Comapct Framework の Font プロパティの getter は、
> アクセスするたびに、新しい Font インスタンスを
> 生成する実装になっている可能性が高いことが伺えます。

解説ありがとうございます。
確かにgetterで新しいインスタンスを返すのであるならば
意味ないと思います。

textBox1.Font = f1;
上記のsetterで新しいインスタンスが生成されるという
ことは考えられないでしょうか?
この考えでもつじつまがあうように思いました。



引用返信 編集キー/
■91541 / inTopicNo.30)  Re[12]: メモリリークに関して
□投稿者/ 魔界の仮面弁士 (2221回)-(2019/07/04(Thu) 15:18:05)
2019/07/04(Thu) 15:29:28 編集(投稿者)

No91540 (kiku さん) に返信
> textBox1.Font = f1;
> 上記のsetterで新しいインスタンスが生成されるという
> ことは考えられないでしょうか?

仮に setter でインスタンスが生成されていたとしても、
それと別に、getter で毎回生成されていることは間違いないかと。


using (var txt = new TextBox())
{
 // CE 環境においては "違う" らしい
 MessageBox.Show(ReferenceEquals(txt.Font, txt.Font) ? "同じ" : "違う");
}
using (var txt = new TextBox { Font = null })
{
 // "not null" と表示される
 MessageBox.Show((txt.Font == null) ? "null" : "not null");
}



No91539 (魔界の仮面弁士) に追記
> var f1 = new Font(FontFamily.GenericMonospace, 12, FontStyle.Regular);
> var f2 = new Font(FontFamily.GenericMonospace, 12, FontStyle.Regular);
> f2.Dispose();
> button1.Font = f1;
> button2.Font = f2;
> button1.Font.Dispose();
>
> .NET Compact Framework の場合は、button1 だけが新しいフォントになります。
> button2 の方は以前のフォントのままレンダリングされていました。

違ってました。

デザイン時に別のフォントを指定してから実行してみると、
button2 のフォントが変化する様子が確認できたので、
button2 が「以前のフォントのまま」で変化しないという推察は誤りですね。

Control.Font プロパティに「Dispose 済みの Font」や「null」が渡された場合、
『既定のフォントがセットされる』という動作になっているようです。
引用返信 編集キー/
■91543 / inTopicNo.31)  Re[13]: メモリリークに関して
□投稿者/ 魔界の仮面弁士 (2223回)-(2019/07/04(Thu) 15:26:21)
No91541 (魔界の仮面弁士) に追記
> Control.Font プロパティに「Dispose 済みの Font」や「null」が渡された場合、
> 『既定のフォントがセットされる』という動作になっているようです。


そもそも Font プロパティで内部管理されているものは、
Font オブジェクトのインスタンスそのものではなく、
それが指し示すアンマネージなハンドルっぽい?


// Compact Framework の Font オブジェクトの内部ハンドルを得る
static IntPtr GetHandle(Font f)
{
  BindingFlags bf = BindingFlags.NonPublic | BindingFlags.Instance;
  FieldInfo field = typeof(Font).GetField("m_htx", bf);
  if (field == null || f == null)
  {
    return IntPtr.Zero;
  }
  else
  {
    return (IntPtr)field.GetValue(f);
  }
}


private void button1_Click(object sender, EventArgs e)
{
  using (var f1 = new Font(FontFamily.GenericMonospace, 12, FontStyle.Regular))
  using (var f2 = new Font(FontFamily.GenericMonospace, 12, FontStyle.Regular))
  {
    // 別のインスタンスだけど、同じハンドルが得られている。
    // String でいうところの 文字列インターンプールのようなものだろうか?
    var h1 = GetHandle(f1);
    var h2 = GetHandle(f2);
    MessageBox.Show((h1 == h2) ? "同じ" : "違う");

    // 一方のインスタンスを破棄してみる
    f1.Dispose();

    // 破棄した方からは IntPtr.Zero が返される。
    var h3 = GetHandle(f1);
    var h4 = GetHandle(f2);
    MessageBox.Show((h3 == h4) ? "同じ" : "違う");
  }
}





引用返信 編集キー/
■91544 / inTopicNo.32)  Re[13]: メモリリークに関して
□投稿者/ kiku (113回)-(2019/07/04(Thu) 16:08:32)
No91541 (魔界の仮面弁士 さん) に返信
> 2019/07/04(Thu) 15:29:28 編集(投稿者)
> 仮に setter でインスタンスが生成されていたとしても、
> それと別に、getter で毎回生成されていることは間違いないかと。

こちらでも動作させてみました。
確かにgetterで間違いないですね。
勝手にDisposeさせないための仕様なのかわかりませんが、
なんかしっくりこないですね。

> Control.Font プロパティに「Dispose 済みの Font」や「null」が渡された場合、
> 『既定のフォントがセットされる』という動作になっているようです。

ありがとうございます。
Fontは常に有効なインスタンスを保持しているような動作になると
理解しました。

引用返信 編集キー/
■91545 / inTopicNo.33)  Re[14]: メモリリークに関して
□投稿者/ kiku (114回)-(2019/07/04(Thu) 16:12:40)
No91543 (魔界の仮面弁士 さん) に返信
> ■No91541 (魔界の仮面弁士) に追記
>>Control.Font プロパティに「Dispose 済みの Font」や「null」が渡された場合、
>>『既定のフォントがセットされる』という動作になっているようです。
> そもそも Font プロパティで内部管理されているものは、
> Font オブジェクトのインスタンスそのものではなく、
> それが指し示すアンマネージなハンドルっぽい?

なるほど。
こんなに深く考えたことがなかったので
勉強になります。

引用返信 編集キー/
■91546 / inTopicNo.34)  Re[15]: メモリリークに関して
□投稿者/ kiku (115回)-(2019/07/04(Thu) 16:14:33)
ここまでの情報や実験結果を用いてどのように対処していくのか
方向性を出したいと思っています。
少し考えさせてください。
引用返信 編集キー/
■91569 / inTopicNo.35)  Re[16]: メモリリークに関して
□投稿者/ kiku (116回)-(2019/07/08(Mon) 11:36:04)
No91546 (kiku さん) に返信
> ここまでの情報や実験結果を用いてどのように対処していくのか
> 方向性を出したいと思っています。
> 少し考えさせてください。

下記のような対応にて、様子を見ることになりました。
Font.Dispose()については、意味がないことを説明したのですが、
ご理解得ることはできなかったため、実装しています。
実装しても弊害が発生することはないと思いますので。
結果が出るまでに、時間がかかると思いますので
ここで解決済みとします。

    partial class Test
    {
        private System.ComponentModel.IContainer components = null;

        protected override void Dispose(bool disposing)
        {
            CustomDispose.Dispose(this.Controls);//★対策追加
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        private void InitializeComponent()
        {
            this.lbl_serialnumber = new System.Windows.Forms.Label();
            this.SuspendLayout();
            // 
            // lbl_serialnumber
            // 
            this.lbl_serialnumber.BackColor = System.Drawing.Color.White;
            this.lbl_serialnumber.Font = new System.Drawing.Font("MS ゴシック", 16F, System.Drawing.FontStyle.Bold);
            this.lbl_serialnumber.Location = new System.Drawing.Point(5, 115);
            this.lbl_serialnumber.Name = "lbl_serialnumber";
            this.lbl_serialnumber.Size = new System.Drawing.Size(310, 20);
            this.lbl_serialnumber.Text = "lbl_serialnumber";
            // 
            // Test
            // 
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
            this.ClientSize = new System.Drawing.Size(640, 480);
            this.ControlBox = false;
            this.Controls.Add(this.lbl_serialnumber);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.Name = "Test";
            this.Text = "Test";
            this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
            this.ResumeLayout(false);
        }

        private System.Windows.Forms.Label lbl_serialnumber;
    }

    //★ここ以降対策追加
    public class CustomDispose
    {
        static public void Dispose(Control.ControlCollection Controls)
        {
            foreach (var c in Controls)
            {
                Logger.Info(c.GetType().ToString());
                switch (c.GetType().FullName)
                {
                    case "System.Windows.Forms.Label":
                        ((System.Windows.Forms.Label)c).Font.Dispose();
                        ((System.Windows.Forms.Label)c).Dispose();
                        break;
                    //ここにTextBoxなどの他のコントロールも多数存在する。
                    //ここにカスタムコントロールも多数存在する。
                    default:
                        //●解放漏れの可能性あり●
                        break;
                }
            }
        }
    }


引用返信 編集キー/
■91570 / inTopicNo.36)  Re[17]: メモリリークに関して
□投稿者/ kiku (117回)-(2019/07/08(Mon) 11:36:37)
解決済み
解決済み
引用返信 編集キー/
■91571 / inTopicNo.37)  Re[17]: メモリリークに関して
□投稿者/ 魔界の仮面弁士 (2226回)-(2019/07/08(Mon) 14:19:34)
No91569 (kiku さん) に返信
> foreach (var c in Controls)
> {
>     Logger.Info(c.GetType().ToString());
>     switch (c.GetType().FullName)
>     {
>         case "System.Windows.Forms.Label":
>             ((System.Windows.Forms.Label)c).Font.Dispose();
>             ((System.Windows.Forms.Label)c).Dispose();

型ではなく型名でチェックしている点が気になりますが、それはさておき。


Form 上に Panel や TabControl 等を使用していた場合、this.Controls だけではなく
その配下のコントロールも再帰的に処理する必要があるのではないでしょうか。
(this.Controls[0].Controls 的な意味で)

https://stackoverflow.com/questions/2209854/find-all-child-controls-of-specific-type-using-enumerable-oftypet-or-linq



> protected override void Dispose(bool disposing)
> {
>     CustomDispose.Dispose(this.Controls);//★対策追加
>     if (disposing && (components != null))
>     {
>         components.Dispose();
>     }
>     base.Dispose(disposing);
> }

マネージリソースを破棄するのは、disposing == true の時だけなのでは?

# 一応、解決済みマークはつけたままにしておきます。

解決済み
引用返信 編集キー/
■91572 / inTopicNo.38)  Re[18]: メモリリークに関して
□投稿者/ kiku (118回)-(2019/07/09(Tue) 10:26:26)
No91571 (魔界の仮面弁士 さん) に返信
>>foreach (var c in Controls)
>>{
>> Logger.Info(c.GetType().ToString());
>> switch (c.GetType().FullName)
>> {
>> case "System.Windows.Forms.Label":
>> ((System.Windows.Forms.Label)c).Font.Dispose();
>> ((System.Windows.Forms.Label)c).Dispose();
>
> 型ではなく型名でチェックしている点が気になりますが、それはさておき。

switch (c.GetType())
{
case typeof(System.Windows.Forms.Label):
((System.Windows.Forms.Label)c).Font.Dispose();
((System.Windows.Forms.Label)c).Dispose();

こんな感じにしてみたのですが、ビルドできなかったので、
if文の羅列になってしまいます。
好みの問題なのですが、switch文の方が見た目がきれいなので
こちらにしてみました。
swich文でも書き方によってうまくできればよいのですが。

> Form 上に Panel や TabControl 等を使用していた場合、this.Controls だけではなく
> その配下のコントロールも再帰的に処理する必要があるのではないでしょうか。
> (this.Controls[0].Controls 的な意味で)

今回のアプリでは全画面にどんなコントロールが利用されているのかを
把握しています。
コンテナとなるようなコントロールは無いことを確認しているため、
実装していません。

> マネージリソースを破棄するのは、disposing == true の時だけなのでは?

確かにそうですね。
コメントありがとうございます。
対応させて頂きます。
解決済み
引用返信 編集キー/
■91585 / inTopicNo.39)  Re[19]: メモリリークに関して
□投稿者/ shu (1185回)-(2019/07/10(Wed) 15:55:13)
2019/07/10(Wed) 16:18:04 編集(投稿者)

No91572 (kiku さん) に返信

>
> switch (c.GetType())
> {
> case typeof(System.Windows.Forms.Label):
> ((System.Windows.Forms.Label)c).Font.Dispose();
> ((System.Windows.Forms.Label)c).Dispose();
>
> こんな感じにしてみたのですが、ビルドできなかったので、
> if文の羅列になってしまいます。
> 好みの問題なのですが、switch文の方が見た目がきれいなので
> こちらにしてみました。
> swich文でも書き方によってうまくできればよいのですが。
>

C#はswitchでこの要件を満足するのは厳しいと認識しております。
一応次のようにすれば可能

int a = c is Label ? 1 :
c is Button ? 2 :
-1;

switch (a)
・・・





解決済み
引用返信 編集キー/
■91586 / inTopicNo.40)  Re[20]: メモリリークに関して
 
□投稿者/ 魔界の仮面弁士 (2232回)-(2019/07/10(Wed) 16:37:37)
No91585 (shu さん) に返信
> C#はswitchでこの要件を満足するのは厳しいと認識しております。
> 一応次のようにすれば可能

C# の言語仕様的には一応、C# 7.0 以降で
「型による分岐」がサポートされるようになっていたりします。

今回は VS2008 (C# 3.0) なので使えないですが…。


foreach (Control c in Controls )
{
 switch (c)
 {
  case System.Windows.Forms.Label _:
  case System.Windows.Forms.TextBox _:
   c.Font.Dispose();
   c.Dispose();
   break;
 }
}

// ----------------

foreach (Control c in Controls )
{
 switch (c)
 {
  case System.Windows.Forms.Label lbl:
   lbl.Font.Dispose();
   lbl.Dispose();
   break;
  case System.Windows.Forms.PictureBox pic:
   pic.Image?.Dispose();
   pic.BackgroundImage?.Dispose();
   pic.Dispose();
   break;
 }
}

ただし、型による分岐はジャンプ命令に変換されないので、
内部的には if 分岐と変わらなくなりますね。
解決済み
引用返信 編集キー/

このトピックをツリーで一括表示

<前の20件 | 次の20件>
トピック内ページ移動 / << 0 | 1 | 2 >>

管理者用

- Child Tree -