none
子フォームから親フォームのintひとつだけを取得・設定したい RRS feed

  • 質問

  • 子フォームから親フォームの値を取得・設定する場合は

    http://homepage3.nifty.com/midori_no_bike/CS/index.html?form.211

    ここを参考にし

    Form2 form2 = new Form2() ; // 子 Form2 を生成

    form2.form1 = this ; // 子 Form2 の参照ポインタを設定

    form2.Show() ;

    これでForm2からForm1の値を取得・設定できますが

    Form1が巨大であった場合

    form2.form1 = this

    の部分がintひとつだけを参照したいのメモリを無駄に消費してしまいます。

    値ひとつだけというのはどうしたらよいのでしょうか?

    ちなみに

    ---------------------Form1---------------------

    public int a = 0;

    ---------------------Form2---------------------

    int b = ((Form1)this.Owner).a;

    とすると

    参照マーシャリング クラスのフィールドであるため、'メンバー' のメンバーにアクセスすると、ランタイム例外が発生する可能性があります

    http://msdn.microsoft.com/ja-jp/library/x524dkh4%28v=VS.100%29.aspx

    と警告されてしまいます。

    よき方法をご存知の方教えていただけましたら幸いです。

    2011年11月12日 3:14

すべての返信

  • > Form1が巨大であった場合
    > form2.form1 = this
    > の部分がintひとつだけを参照したいのメモリを無駄に消費してしまいます。

    Form1 のインスタンスは一つしかなさそうですが、であれば、「メモリを無駄
    に消費」ということはなさそうですが・・・

    見当違いだったら失礼しました。

     

     

    2011年11月12日 3:24
  • Form1が巨大であった場合
    form2.form1 = this
    の部分がintひとつだけを参照したいのメモリを無駄に消費してしまいます。

    .NET の型には値型と参照型があります。
    Form1 はクラス、参照型ですので、代入式でコピーされることはありません。あくまで、実体を参照するための情報がコピーされるだけですので、たかだか数バイトレベルでしょう。

    詳しいことは、.NET のメモリ管理周りの情報を調べて勉強してください。

    参照マーシャリング クラスのフィールドであるため、'メンバー' のメンバーにアクセスすると、ランタイム例外が発生する可能性があります

    http://msdn.microsoft.com/ja-jp/library/x524dkh4%28v=VS.100%29.aspx

    と警告されてしまいます。
    よき方法をご存知の方教えていただけましたら幸いです。

    そこの説明、サンプルに解決方法書いていますよ。

    # 個人的にはこんな循環参照はおすすめできませんが…。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2011年11月12日 3:47
    モデレータ
  • ># 個人的にはこんな循環参照はおすすめできませんが…。

    同感です。

    「子が、親のあずかり知らぬ所(タイミング)で親の持つ値を参照する」ようなことは避けるべきです。

    親から子に与えるか、イベントを使うなど、シナリオに応じたもっと良い解決方法があるはずです。

     

    2011年11月12日 4:09
    モデレータ
  • 皆さんご返信ありがとうございます。

    まず、メモリ消費の件ですがどうやら私の勘違いのようで他の処理で大きくなってました。

    誤解を正してくれてありがとうございます。

    次に本題ですが、

    form2.form1 = this ;

    これはあまりよくない

    // CS1690.cs
    using System;
    
    class WarningCS1690: MarshalByRefObject
    {
       int i = 5;
    
       public static void Main() 
       {
         WarningCS1690 e = new WarningCS1690();
         e.i.ToString();   // CS1690
    
         // OK
         int i = e.i;
         i.ToString();
         e.i = i;
       }
    }

    マイクロソフトのホームページにのっているこれもだめとなる

    親と子でintをうまく共有できるお勧めできる方法は他に渋木さんがイベントを使うのがいいとのことですが

    どんなイベントがいいのか見当がつかない状態です。

    2011年11月12日 4:37
  • > これはあまりよくない

    これでいいと思いますけど。何故「あまりよくない」と判断されたので
    しょうか?

     

    2011年11月12日 5:14
  • 読み間違えたかもしれません。

    循環参照はよくないと皆さんおっしゃられてたので

    これはMSDNの例のことだけですか?

    form2.form1 = this ;

    これに関しては皆さんありですか?

    だとしたらすいませんでした。

    2011年11月12日 5:27
  • 循環参照が全面的に悪というわけではありませんし

    >form2.form1 = this ;

    のような参照の仕方が全面的に悪というわけでもありません。(コンパイルは通るし、何を破壊するわけでもないし)

    「それで十分」な場合ももちろんあります。

    僕が「好ましくない」と考えるのは、僕が「それで十分でない」場合を扱うことが多いからです。

    決めつけで書いてしまってすみません。


    2011年11月12日 6:14
    モデレータ
  • 循環参照はMSDNの例についてだと思いますが、循環参照になるんですっけ・・・? 例は全体的にはおかしなコードですが、一つ一つについては、こんなことはやってもOKということを示しているのだと思いました。
    また、おそらく渋木さんは、form2.form1 = this ; が良くないと言われているのではないかと思います。
    必要なものだけを子に渡すか、イベントで子に通知した方が良いと言われているのだと思います。
    form2.form1 = this;自体は間違いだとは思いませんが(FormクラスにOwnerプロパティがあったりしますし・・・)、intを一つだけ渡したいのであれば、私もそれだけ渡せば良いと思います。それだけ渡すには、form2にint型のプロパティを作って、そこに渡すだけです。
    form2.int型のプロパティ = form1の渡したい値;

     #あっ、すいません。書きかけで今投稿したら渋木さんが書き込まれた後でした(^^; その部分についてはスルーして下さい。でも、循環参照がどの部分を指しているのかわからなくなってきました・・・


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2011年11月12日 6:30
    モデレータ
  • 「あまりよくない」の理由を考えることが重要だと思っとります。

     

    元の例示コードで、

     form2 を破棄する前に form1 を閉じた場合どのようなことになるでしょう?

     

    オブジェクトの生存期間を意識するのがポイントです。

     

    2011年11月12日 6:36
  • このスレッドのコメントも循環参照されてしまいましたね。

    お後がよろしいようで。

    2011年11月12日 8:06
  • 循環参照はよくないと皆さんおっしゃられてたので
    これはMSDNの例のことだけですか?

    いいえ、MSDN のサンプルは循環参照とはいえません。
    ただ、サンプルのプロパティ・フィールドである i が int から long に変えられたとか、double に変えられたということが起きてもコンパイルエラーなく実行できますが、利用側としては整数の文字列と期待していたのに違う文字列に変化する不具合が発生するかもしれませんね。
    そういう意味では、一時変数に型を明示して代入しておけば、警告・エラーが表示されることで気づくきっかけを与えてくれるという効果が期待できます。

    循環参照は自分がわかってその場限りで使う分には、支障はないと思います。
    ただし、そのコードを保守していく、チームで使っていくようなことがあれば、トラブルの元になるかもしれません。

    このスレッドのコメントも循環参照されてしまいましたね。
    お後がよろしいようで。

    何を言いたいのかわかりませんが、このコメントを好意的にとらえるのは難しいと思います。
    そういう書き捨てる行為は、質問を解消する手段を失うことにつながるかもしれませんよ。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2011年11月12日 9:02
    モデレータ
  • if (e.KeyCode == Keys.Enter & e.Modifiers != Keys.ControlKey)
    このコードを見ていただければご理解いただけると思います。

    このコードと、「if (e.KeyCode == Keys.Enter && e.Modifiers != Keys.ControlKey)」って、同じ結果になるんでしたっけ?

    まぁ、上記のコードでは、同じ結果になるでしょうね。しかし、どんな場合でも必ず同じ結果になるとは限りません。


    これはMSDNの例のことだけですか?

    マイクロソフトのホームページにのっているこれもだめとなる

    なぜですか?ここでは、「循環参照はしない方が良い」といわれています。MSDN に載っている例は、循環参照ではなく、自己参照です。Form が Owner プロパティで Form を参照するのも、自己参照です。自己参照が良くて循環参照を避けるべきと言われるのは、渋木さんのコメントに「「子が、親のあずかり知らぬ所(タイミング)で親の持つ値を参照する」ようなことは避けるべき」と………あれ?渋木さん、これ、継承関係の親子をイメージしていますか?それとも、関係のないクラスであっても、相互に参照しあうことを指していますか?
    今回のケースでは、Form から派生する Form1 と Form2 で、インスタンスの保持という関係での親子、あるいは画面の設計上での親子関係になりますが、参照の方向を一方向だけにするようにするのがベターです。Form1 と Form2 が、互いに知り合ってなければならない、という作り方は、あまり良くありません。これは、「クラス間の関係を疎にする」ことが推奨されているからです。今回は Form1 と Form2 が同じプロジェクトだからいいですが、別のプロジェクトであれば、Visual Studio が循環参照をサポートしていないため、ビルドできません。(2010はできるようなった?)


    Jitta@わんくま同盟
    2011年11月14日 12:04
  • >あれ?渋木さん、これ、継承関係の親子をイメージしていますか?それとも、関係のないクラスであっても、相互に参照しあうことを指していますか?

    「親」「子」はこの場合、単純に「親フォーム」「子フォーム」の意でした。

    2011年11月15日 7:48
    モデレータ