DOBON.NET DOBON.NETプログラミング掲示板過去ログ

オブジェクト参照について

環境/言語:[c#]
分類:[.NET]

こんにちは。myFormからanotherFormを参照して、値を取得するというコードを書きました。
anotherFormではプロパティを書いています。

myFormではプロパティを参照する為に下記のコードを書きました。

var refForm = Application.OpenForms["anotherForm"];
if (refForm != null)
{
//anotherFormのテキストボックスの内容を取得
anotherForm ff = (anotherForm)refForm;
this.textBox1.Text = ff.returnTextBoxString;

このコードは動きましたが、最初は下記のようにコードを書きました。

refForm.returnTextBoxString

このコードは動きませんでした。refFormはanotherFormを参照しているので、動くと思っていましたが、実際はrefFormをanotherFormでキャストすることで動きました。なぜrefForm.returnTextBoxStringは動かないのでしょうか?

まだ勉強不足でオブジェクトとかしっかり理解していないです。ご教授よろしくお願いいたします。

//-----------------------------myForm------------------------------//
using System;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
public partial class myForm : Form
{
//コンストラクター
public myForm()
{
InitializeComponent();
}

//モードレスフォームとしてForm2を起動
private void button2_Click(object sender, EventArgs e)
{
var f = new anotherForm();
f.Show();
}

//実行ボタン
private void button1_Click(object sender, EventArgs e)
{
var refForm = Application.OpenForms["anotherForm"];
if (refForm != null)
{
//anotherFormのテキストボックスの内容を取得
anotherForm ff = (anotherForm)refForm;
this.textBox1.Text = ff.returnTextBoxString;

//anotherFormのラジオボタンを判定する
var receiveValue = ff.returnValue;
if (receiveValue == 1)
{
this.radioButton1.Checked = true;
}
else
{
this.radioButton2.Checked = true;
}
}

}
}
}


//-----------------------------anotherForm------------------------------//
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
public partial class anotherForm : Form
{
//プロパティ。anotherFormのテキストボックスの内容を返す
public string returnTextBoxString
{
get { return this.textBox1.Text; }
}

//プロパティ。anotherFormのどのラジオボタンが押されているか判定。
public int returnValue
{
get
{
if (this.radioButton1.Checked)
{
return 1;
}
else
{
return 2;
};
}
}

public anotherForm()
{
InitializeComponent();
}
}
}
書きましたコードは下記のようになります。

http://kie.nu/1RQJ
■No32317に返信(たけしさんの記事)

Application.OpenForms["anotherForm"] で何が取得できるか理解されている
でしょうか?(MSDN ライブラリを見ましょう)

それに returnTextBoxString プロパティは定義されてないですよね。だから
です。

#エラーが出たときはエラーメッセージをきちんと書きましょう。それは重要
な情報であることが多いです。
WebSurfer さん

ご回答ありがとうございます。
Application.OpenFormsプロパティが何を返すまで調べていませんでした。

調べた所、アプリケーションによって所有されている、現在開いているすべてのフォームが格納された FormCollectionを返す。OpenForms プロパティは、アプリケーションによって所有されているフォームの読み取り専用コレクションを表します。 このコレクションは、インデックス位置または Form の Name によって検索できます。

また、自分が実行できるだろうと勘違いしていたコードを書いたらエラーメッセージとして下記が表示されました。

エラー2はアドバイス頂きました、「returnTextBoxString プロパティは定義されてないですよね」のところだと思いますが、まだ理解できていません。申し訳ありませんが、これはどのような意味なのでしょうか?


エラー 1 割り当て、呼び出し、インクリメント、デクリメント、および新しいオブジェクトの式のみがステートメントとして使用できます。

エラー 2 'System.Windows.Forms.Form' に 'returnTextBoxString' の定義が含まれておらず、型 'System.Windows.Forms.Form' の最初の引数を受け付ける拡張メソッドが見つかりませんでした。using ディレクティブまたはアセンブリ参照が不足しています。
■No32322に返信(たけしさんの記事)
> Application.OpenFormsプロパティが何を返すまで調べていませんでした。

そうではなくて Application.OpenForms["anotherForm"] (即ち、FormCollection.Item プロパティ (String) )
が何を返すかです。

public virtual Form Item[
    string name
] { get; }

ですよね。だからキャストが必要なのです。

このあたりは基本のキですので、よく覚えておいてください。
■No32322に返信(たけしさんの記事)
> エラー2はアドバイス頂きました、「returnTextBoxString プロパティは定義されてないですよね」のところだと思いますが、まだ理解できていません。申し訳ありませんが、これはどのような意味なのでしょうか?

前提として、OpenForms プロパティで得られるのは Form 型で、returnTextBoxString プロパティが定義されているのは anotherForm 型です。

たとえば、Form f = new anotherForm(); とすると f には anotherForm 型のオブジェクトが入っていますが、このコードは「変数 f を Form 型として扱う」という意味のコードになりますので、Form 型に定義されているメソッド・プロパティ・イベントしか参照できないようになります。
このような状況から、元の型である anotherForm 型として扱うためには Form 型から変換=キャストする必要があります。

anotherForm aF = (anotherForm)f;

こうすれば、aF が anotherForm 型ということになりますので、anotherForm 型で追加したプロパティ、returnTextBoxString を使うことができるようになります。

ただし、このようなキャスト(今回の場合はダウンキャストとも呼ばれる)は f の中身が anotherForm 型およびその継承クラスでなければ成功しません。失敗したときは InvalidCastException という実行時エラー(例外)が発生することになります。
今回のケースでは成功すると思いますが、「キャストは失敗することがある」ということだけは覚えておいてください。

また、これを契機に、継承とは何か、ポリモーフィズムとは何かを勉強してみると知識を広げることができるでしょう。
WebSurfer さん 
public virtual Form Item[
string name
] { get; }

辺りがまだよく理解できていません。基本を学んでいてvirtual辺りは本で読んだのですが、いまいち腹に落ちていません。本読み直します。ありがとうございました。
Azulean さん

キャストするべき必要について、とてもわかりやすく勉強になりました。独習C#という本を読んで継承やポリモーフィズムも目は通していたのですが、まだ完全に理解できていません。今一度本を読んで勉強しなおしたいと思います。ありがとうございます。
解決済み!
■No32338に返信(たけしさんの記事)
> WebSurfer さん 
> public virtual Form Item[
>     string name
> ] { get; }
> 
> 辺りがまだよく理解できていません。基本を学んでいてvirtual辺りは本で
> 読んだのですが、いまいち腹に落ちていません。

Item プロパティというのは C# のインデクサのデフォルト名です。(ドキュメ
ントによっては、上記のコードで Item が this になっているかもしれません
が、同じことです)

先の私のレスでは、質問者さんのコード Application.OpenForms["anotherForm"] 
のようにインデクサを使うと何が返されるかは MSDN ライブラリなどで
FormCollection.Item プロパティ (String) を見ると分かるということを言い
ました。

MSDN ライブラリに書いてある通り、Application.OpenForms["anotherForm"] 
で得られるのは Form 型です。

何故、このプロパティで得られた Form 型を anotherForm 型にキャストする必
要があるかの詳しい説明は Azulean さんのレスを読んでください。

なお、virtual は今回の話とは直接関係ないです。(FormCollection クラスを継承したクラスを定義するときにこのプロパティを override できるということです)
WebSurfer さん

ご回答ありがとうございます。今一度MSDNを読み込んでみたいと思います。何度も詳しくありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板