- PR -

VSのウォッチ・ウィンドウで表示されるbaseクラスの値

1
投稿者投稿内容
Furi2
ベテラン
会議室デビュー日: 2004/10/28
投稿数: 74
お住まい・勤務地: N.Hollywood/Agoura Hills
投稿日時: 2007-08-22 07:11
お世話になっています。

以下のようにPropプロパティーをオーバーライドするクラスがあったとします。VS2005で,UpperCaseLetter.Propにステップ・インして、ウォッチ・ウィンドウでbase.Propの値を見ると、"a"という値を期待するのに、"A"が表示されます。もちろん実際には"a"が返ってきて、baseVal変数に格納されるので、動作的には問題ないのですが。。始めわからなくて、アサインする値とされた値が別物に見え、混乱してしまいました。this.Propとbase.Propは、常にthis.Propが表示される感じなのですが、これって何か理由があるんでしょうか。。VSでステップインして、確実に本当のbase.Propをチェックできる方法ってあるんでしょうか?


UpperCaseLetter letter = new UpperCaseLetter("a");
TextBox1.Text = letter.Prop;
-------
public class Letter
{
private string _letter;
public Letter( string letter )
{
_letter = letter;
}
public virtual string Prop
{
get
{
return _letter;
}
}
}

public class UpperCaseLetter : Letter
{

public UpperCaseLetter( string letter ) : base( letter )
{}
public override string Prop
{
get
{
string baseVal = base.Prop; // **** この行でブレイク、ウォッチウィンドウでbase.Propを見ると、"A"となる。
return baseVal.ToUpper();
}
}
}


[ メッセージ編集済み 編集者: Furi2 編集日時 2007-08-22 07:42 ]
masa
大ベテラン
会議室デビュー日: 2004/10/28
投稿数: 161
投稿日時: 2007-08-23 09:10
今どのような型として扱われているかによって処理の内容が変わることはありません。

もし base.Prop の値も必要であり、大文字変換した値をほしい場面が限られているのであれば、override ではなく、PropToUpper() のような別メソッド・プロパティを UpperCaseLetter クラスに追加するのが妥当ではないでしょうか。

masa
大ベテラン
会議室デビュー日: 2004/10/28
投稿数: 161
投稿日時: 2007-08-23 09:13
new なら望んでいる(?)結果になるかな。
乱用すると混乱しますからあまりお勧めはしませんが。

public new string Prop {
 get {
  if ( base.Prop == null ) { return null; }
  return base.Prop.ToUpper();
 }
 set {
  base.Prop = value;
 }
}
masa
大ベテラン
会議室デビュー日: 2004/10/28
投稿数: 161
投稿日時: 2007-08-23 09:39
override と new の違いについての簡単なサンプルです。

// 基底の型
public class a {
  public a( string name ) {
    m_Name = name;
  }
  public virtual string Name {
    get { return m_Name; }
  }
  private string m_Name;
}

// name プロパティを override
public class b : a {
  public b( string name ) :base(name){
  }
  public override string Name {
    get { return base.Name.ToUpper(); }
  }
}

// name プロパティを new
public class c : a {
  public c( string name )
    : base( name ) {
  }
  public new string Name {
    get { return base.Name.ToUpper(); }
  }
}

private void test() {

  System.Diagnostics.Debug.WriteLine( new a( "aaa" ).Name );
  System.Diagnostics.Debug.WriteLine( new b( "bbb" ).Name );
  System.Diagnostics.Debug.WriteLine( new c( "ccc" ).Name );

  // 基底の型を引数としている汎用関数で name を取得
  System.Diagnostics.Debug.WriteLine( GetName( new a( "aaa" ) ) );
  System.Diagnostics.Debug.WriteLine( GetName( new b( "bbb" ) ) );
  System.Diagnostics.Debug.WriteLine( GetName( new c( "ccc" ) ) );

}

private string GetName( a value ) {
  // a 型として扱われます
  return value.Name;
}

// 実行結果

  aaa
  BBB
  CCC
  aaa
  BBB ← override された name プロパティの内容が実行される
  ccc ← a 型の name プロパティの内容が実行される

直接 c 型として扱われている場合とそうでない場合で結果が変わります。
これを良しとする、こうあって欲しい場面はそれほど多くはないと思います。
Furi2
ベテラン
会議室デビュー日: 2004/10/28
投稿数: 74
お住まい・勤務地: N.Hollywood/Agoura Hills
投稿日時: 2007-08-23 10:10
ご返答ありがとうございます。
ちょっと私の書き方が悪かったかもしれません。overrideとnewの違いはわかっているつもりです。私が挙げたサンプルコードも、動作的には全く問題ありませんし、期待する結果を出してくれます。
ですがVSでブレークポイントを置いてステップインした時に、期待する値を表示しない、ということです。
私のコードでいうと、指定した行のbase.Propから戻ってくる値は、その時点ではあくまで"a"ですよね。なので変数baseValueの値は"a"となり、結果としてthis.Propは"A"を返します。しかしステップインすると、baseValueの値は"a"と表示され、それは期待どおりですが、base.Propは"A"となっていて、実際に返ってきている値と違うものが表示されているということです。

masaさんのコードでいうと、b.Nameにステップインした時、base.Nameから"bbb"を受け取り、それをToUpperで"BBB"にしてreturnしているわけなので、ウォッチ・ウィンドウでは、base.Name="bbb"、this.Name="BBB"と表示してほしい、と思うのです。実際その時点でbase.Nameから戻ってきている値は"bbb"なわけですから。しかしVSのウォッチ・ウィンドウでは、base.Nameもthis.Nameも、両方"BBB"と表示されます。

あくまでデバッグ中にクラスのコード内に"ステップインした時"に何がデバッグ・ウィンドウに表示されるか、の話でした。C#がオーバーライド、またはnewした時に、結果に何を返すか、の話ではありませんでした。すみません、わかりにくくて。

public class b : a {
  public b( string name ) :base(name){
  }
  public override string Name {
    get { return base.Name.ToUpper(); }
  }
}
masa
大ベテラン
会議室デビュー日: 2004/10/28
投稿数: 161
投稿日時: 2007-08-23 10:20
デバッグウィンドウは、指定されたオブジェクトの内容をリフレクションを使って読み取って表示するものですから、通常のアプリケーションコードで実行時に値を取得するのと同じような結果( override された後の定義に基づく結果)となります。

override しているプロパティの中をステップインで見ている場合は、
override 前の定義に基づく結果ですから(表現変かも)、基底の処理結果が返ってくるのではないでしょうか。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2007-08-26 22:08
すっかり遅れてしまいました。

おそらく、masaさんが書かれているとおり。

 VS.NET2003 で "base.Prop" をクイック ウォッチしようとすると、できませんでした。base.Prop がスコープの中にない、と。で、VS2005 で試すと、 "base.Prop" は見えました。しかし、base を見ることはできませんでした。base キーワードの使用は、このコンテキストでは正しくない、と。
 それはそうですね。base は、変数ではなくキーワードで、クラスの中でしか使えませんから。


 試しに、UpperCaseLetter.Props でブレークしているときに this をクイック ウォッチすると、中に base とあります。この base を選択すると、「((Letter)(this))」と、this をキャストしていることがわかります。これは、VS2005 でも同じです。

 つまり、クイック ウォッチで見る限り、UpperCaseLetter のインスタンスを外部から見ているので、オーバーライドしているプロパティはオーバーライドされた結果が見える、といえるでしょう。
 base が見えるように VS2005 で便利にしてくれたけど、VS.NET2003 のように base.Prop は見えないままにしておく、あるいは this からキャストされていることがわかるように表示されれば、混乱することはないのかもしれませんね。


 で、最初に戻って、「確実に本当のbase.Propをチェックできる方法ってあるんでしょうか?」について。

base はクラスの外からアクセスできません。
デバッガは、クラスの外からアクセスします。
従って、base にアクセスできないため、チェックする方法はありません。
Furi2
ベテラン
会議室デビュー日: 2004/10/28
投稿数: 74
お住まい・勤務地: N.Hollywood/Agoura Hills
投稿日時: 2007-08-28 02:25
Jittaさん、masaさん、レスありがとうございました。

引用:

((Letter)(this))
base はクラスの外からアクセスできません。
デバッガは、クラスの外からアクセスします。
従って、base にアクセスできないため、チェックする方法はありません。


なるほど、、すごく納得です。。わかりやすく説明してくださって、ありがとうございました!とても勉強になりました。またいつかよろしくお願いいたします。
1

スキルアップ/キャリアアップ(JOB@IT)