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

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

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

Re[1]: Withで親を使う方法


(過去ログ 138 を表示中)

[トピック内 3 記事 (1 - 3 表示)]  << 0 >>

■81275 / inTopicNo.1)  Withで親を使う方法
  
□投稿者/ ベア (1回)-(2016/09/05(Mon) 23:53:24)

分類:[.NET 全般] 


Withを使えば以下のようにドットをつけるだけで子アイテムに数値を入れることができます。


With aaa.bbb.ccc.Button1
.Text = "Withですか?"
.BackColor = Color.LightBlue
.TextAlign = ContentAlignment.MiddleRight
End With


一方で、親アイテムに数値を入れたい場合にはどうしたら良いですか?


With aaa.bbb.ccc.Button1
aaa.bbb.ccc.Button1 = ddd
End With

このようにWithの中であっても省略せずに書くしかないのでしょうか?

引用返信 編集キー/
■81276 / inTopicNo.2)  Re[1]: Withで親を使う方法
□投稿者/ shu (912回)-(2016/09/06(Tue) 00:17:11)
No81275 (ベア さん) に返信
> 
> Withを使えば以下のようにドットをつけるだけで子アイテムに数値を入れることができます。
数値だけでなくその他の型でも使えます。

> 
> 
> With aaa.bbb.ccc.Button1
>     .Text = "Withですか?"
文字列です。

>     .BackColor = Color.LightBlue
Color型の値です。

>     .TextAlign = ContentAlignment.MiddleRight
列挙型の値です。これは数値と言えなくはないですが。

> End With



> 
> 一方で、親アイテムに数値を入れたい場合にはどうしたら良いですか?
> 
> 
> With aaa.bbb.ccc.Button1
>     aaa.bbb.ccc.Button1 = ddd
> End With
> 

With aaa.bbb.ccc
    .Button1 = ddd
End With
と書けます。


連続した上記と連続したコードなのなら
With aaa.bbb.ccc
    With .Button1
        .Text = "Withですか?"
        .BackColor = Color.LightBlue
        .TextAlign = ContentAlignment.MiddleRight
    End With
    .Button1 = ddd
End With
となります。


.Button1=dddが最初なら

aaa.bbb.ccc.Button1 = ddd
With ddd
    .Text = "Withですか?"
    .BackColor = Color.LightBlue
    .TextAlign = ContentAlignment.MiddleRight
End With

とした方がよいかと思います。


引用返信 編集キー/
■81278 / inTopicNo.3)  Re[1]: Withで親を使う方法
□投稿者/ 魔界の仮面弁士 (881回)-(2016/09/06(Tue) 10:39:41)
2016/09/06(Tue) 11:22:24 編集(投稿者)

# 既に回答が付いていますが補足の意味も込めて。

No81275 (ベア さん) に返信
> 数値を入れることができます。
「数値」に限定しているわけでは無いので、
この場合は「値」ですね。


> 一方で、親アイテムに数値を入れたい場合にはどうしたら良いですか?
With の中で With の参照先を入れ替えるのは
基本的に NG であると考えておいてください。


実は「With ステートメント」というものは、
  With aaa.bbb.ccc.Button1
   .Text = "Withですか?"
   .BackColor = Color.LightBlue
   .TextAlign = ContentAlignment.MiddleRight
  End With
というコードを、一時変数を用いた
  Dim [$W0] = aaa.bbb.ccc.Button1
  [$W0].Text = "Withですか?"
  [$W0].BackColor = Color.LightBlue
  [$W0].TextAlign = ContentAlignment.MiddleRight
という呼び出しにコンパイルするという動作になっています。
(VB では $ で始まる変数名を宣言できないため、あくまで処理イメージですが)


> With aaa.bbb.ccc.Button1
>   aaa.bbb.ccc.Button1 = ddd
> End With
> このようにWithの中であっても省略せずに書くしかないのでしょうか?

いえ、そのような呼び方も本来は NG です。
言語仕様的には問題無いとはいえ、非常に分かりにくいコードになってしまいます。

たとえば
  With aaa.bbb.ccc.Button1
    .Text = "Before"
    aaa.bbb.ccc.Button1 = ddd
    .Text = "After"
  End With
のようなコードがあったとしましょう。

この場合、"After" は、一見すると ddd への操作に見えますが、
実際には ddd.Text ではなく、差し替え前の Button1.Text への操作になます。


これは、「.Text = "Before"」や「.Text = "After"」が操作しているのは、
実際には Button1 そのものではなく、With で指定した Button1 への参照を
保持している一時変数「$W0」であるためです。

そのため、With の途中で Button1 の指し示す先を変更したとしても、
$W0 が指しているのは、変更前のインスタンスというわけです。


ちなみにこれは、ByRef 引数な拡張メソッドの呼び出しにも影響します。

=================
Imports System.Runtime.InteropServices
Imports System.Runtime.CompilerServices
Module SampleExtensions
  '★拡張メソッドの最初の引数を参照渡しにしておく★
  <Extension()> Public Sub ChangeInstance(Of T)(<Out()> ByRef this As T, ByVal newInstance As T)
    this = newInstance '★インスタンスの入れ替え★
  End Sub
End Module
=================

上記の拡張メソッドを用意しておくと、
  aaa.bbb.ccc.Button1.ChangeInstance(ddd)
のようにして、Button1 の参照先を ddd へと差し替えできます。
差し替え前の Button1 は Nothing であったとしても構いません。

しかしこれを、「With aaa.bbb.ccc.Button1」のブロック内で
『.ChangeInstance(ddd)』と呼び出した場合には、
aaa.bbb.ccc.Button1 が指すインスタンスは ddd にはならないのです。

どうやらこのような呼び出し方だと、ByRef 引数への呼び出しが
ByVal 相当の動作で呼び出されるようになっているようなのです。
混乱を防ぐために意図的にそうしているのか、あるいは単に一時変数で
あるからなのかは定かではないですが、いずれにせよ、このコードで
参照先の変数が指し変わることはありません。


また、仮に ByRef のまま呼び出されることがあったとしても、先ほどと同様、
変更されるのは aaa.bbb.ccc.Button1 自身ではなく、
一時変数 $W0 だけなので、どちらにせよ意味がないのですけれどね。


なお、上記は ddd や aaa.bbb.ccc.Button1 が「参照型」の場合です。

これらが 値型だった場合、$W0 は「値型」ではなく「値型への参照」となり、
例示した ChangeInstance 拡張メソッドによる入れ替えが働きますし、
With ブロック内で「aaa.bbb.ccc.Button1 = ddd」と差し替えたとしても、
その直後から、ddd への操作に切り替わる事になります。
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -