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

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

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

byrefと参照の違いについて

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

■83096 / inTopicNo.1)  byrefと参照の違いについて
  
□投稿者/ はーと (1回)-(2017/03/06(Mon) 18:04:05)

分類:[.NET 全般] 

byrefと参照がどう違うのか教えてください
引用返信 編集キー/
■83099 / inTopicNo.2)  Re[1]: byrefと参照の違いについて
□投稿者/ 魔界の仮面弁士 (1160回)-(2017/03/06(Mon) 19:16:30)
2017/03/06(Mon) 19:45:17 編集(投稿者)

No83096 (はーと さん) に返信
> byrefと参照がどう違うのか教えてください

質問文が短すぎて、どういう点について知りたいのか意図がよく分かりませんでしたが、
ひとまず「参照型」と「値型」の違いは把握しているものとして、
「ByVal」と「ByRef」について実例を挙げてみます。

Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
  Me.TextBox1.Text = "TextBox1"
  Me.TextBox2.Text = "TextBox2"
  Me.TextBox3.Text = "TextBox3"
  Me.TextBox4.Text = "TextBox4"
  Me.TextBox5.Text = "TextBox5"
  Me.TextBox6.Text = "TextBox6"
End Sub

'-----------------------------------

Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
  '変数 txt1 は「TextBox1」への『参照』を保持している
  '変数 txt2 は「TextBox2」への『参照』を保持している
  Dim txt1 As TextBox = Me.TextBox1
  Dim txt2 As TextBox = Me.TextBox2
  Test1(txt1)
  Test2(txt2)
  MsgBox(txt1.Text)  '「TextBox5」
  MsgBox(txt2.Text)  '「TextBox2」
End Sub

Private Sub Test1(ByRef txt As TextBox) '参照情報がそのまま渡される
  txt = Me.TextBox5  '参照渡しされた仮引数 txt の参照先を書き換えると、実引数 txt1 の参照先も書き変わる
End Sub

Private Sub Test2(ByVal txt As TextBox) '参照情報のコピーが渡される
  txt = Me.TextBox6  '値渡しされた仮引数 txt の参照先を書き換えても、実引数 txt2 の参照先は TextBox2 のまま
End Sub


'-----------------------------------

Private Sub Button2_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button2.Click
  '変数 txt3 は「TextBox3」への『参照』を保持している
  '変数 txt4 は「TextBox4」への『参照』を保持している
  Dim txt3 As TextBox = Me.TextBox3
  Dim txt4 As TextBox = Me.TextBox4
  Test3(txt3)
  Test4(txt4)
  MsgBox(txt3.Text)  '「Test1」
  MsgBox(txt4.Text)  '「Test2」
End Sub

Private Sub Test3(ByRef txt As TextBox) '参照情報がそのまま渡される
  txt.Text = "Test1"    '参照先は TextBox3 なので、Me.TextBox3.Text = "Test1" と同義
End Sub

Private Sub Test4(ByVal txt As TextBox) '参照情報のコピーが渡される
  txt.Text = "Test2"    '参照先は TextBox4 なので、Me.TextBox4.Text = "Test2" と同義
End Sub
引用返信 編集キー/
■83106 / inTopicNo.3)  Re[2]: byrefと参照の違いについて
□投稿者/ はーと (2回)-(2017/03/06(Mon) 22:17:55)
どれも同じで引数に代入してるがtest2だけ変わらない
byvalだからtextboxはそのままだと値型として代入される
合ってますか?
引用返信 編集キー/
■83108 / inTopicNo.4)  Re[3]: byrefと参照の違いについて
□投稿者/ はーと (3回)-(2017/03/06(Mon) 22:25:31)
byvalでも文字列として代入したら変わる
stringは参照型として代入するから
だんだんわかってきました
引用返信 編集キー/
■83110 / inTopicNo.5)  Re[4]: byrefと参照の違いについて
□投稿者/ はーと (4回)-(2017/03/06(Mon) 22:32:18)
ありがとうございます!
解決済み
引用返信 編集キー/
■83111 / inTopicNo.6)  Re[3]: byrefと参照の違いについて
□投稿者/ 魔界の仮面弁士 (1164回)-(2017/03/06(Mon) 22:46:00)
2017/03/06(Mon) 22:56:25 編集(投稿者)

No83106 (はーと さん) に返信
> byvalだからtextboxはそのままだと値型として代入される
> 合ってますか?

全然違います。TextBox クラスはどうあっても参照型です。

参照型と参照渡し、値型と値渡しは用語としては似ていますが
それぞれ別の仕組みなので、混同せぬようご注意下さい。


先ほどのは参照型(TextBox クラス)のサンプルだったので、
今度は値型(Point 構造体)で、ByRef/ByVal の違いを見てみましょう。


TextBox の場合と Point の場合とで、
Test3 の結果に差異がある点に着目してみてください。


Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
  '変数 p1 は Point 構造体で示される座標値 {X = 111, Y = 112} を保持している
  '変数 p2 は Point 構造体で示される座標値 {X = 121, Y = 122} を保持している
  Dim p1 As New Point(111, 112)
  Dim p2 As New Point(121, 122)
  Test1(p1)
  Test2(p2)
  MsgBox(p1.ToString()) '{X=1111,Y=2112} に書き換わる
  MsgBox(p2.ToString()) '{X=121,Y=122} のまま
End Sub

Private Sub Test1(ByRef p As Point)
  p.X += 1000
  p.Y += 2000
End Sub

Private Sub Test2(ByVal p As Point)
  p.X += 3000
  p.Y += 4000
End Sub

'-----------------------------------

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
  '変数 p3 は Point 構造体で示される座標値 {X = 211, Y = 212} を保持している
  '変数 p4 は Point 構造体で示される座標値 {X = 221, Y = 222} を保持している
  Dim p3 As New Point(211, 212)
  Dim p4 As New Point(221, 222)
  Test3(p3)
  Test4(p4)
  MsgBox(p3.ToString()) '{X=999,Y=888} に書き換わる
  MsgBox(p4.ToString()) '{X=221,Y=222} のまま
End Sub

Private Sub Test3(ByRef p As Point)
  p = New Point(999, 888)
End Sub

Private Sub Test4(ByVal p As Point)
  p = New Point(777, 666)
End Sub
引用返信 編集キー/
■83116 / inTopicNo.7)  Re[4]: byrefと参照の違いについて
□投稿者/ はーと (5回)-(2017/03/07(Tue) 09:00:01)
byrefで代入されると必ず変わる
byvalでは値型では絶対に変わらない
textboxが問題ですね
同じbyvalで変わるし変わらないときがある
参照型の値渡しは不定動作?
引用返信 編集キー/
■83119 / inTopicNo.8)  Re[1]: byrefと参照の違いについて
□投稿者/ Jitta (277回)-(2017/03/07(Tue) 09:30:36)
No83096 (はーと さん) に返信
> byrefと参照がどう違うのか教えてください

ByRef 主にVisualBasic で使われる、関数の引数を参照渡しするときのキーワード。
参照 サ変名詞 他のものを照らし合わせて参考にすること。
引用返信 編集キー/
■83122 / inTopicNo.9)  Re[5]: byrefと参照の違いについて
□投稿者/ WebSurfer (1159回)-(2017/03/07(Tue) 10:10:44)
No83116 (はーと さん) に返信
> byrefで代入されると必ず変わる
> byvalでは値型では絶対に変わらない
> textboxが問題ですね
> 同じbyvalで変わるし変わらないときがある
> 参照型の値渡しは不定動作?

ごっちゃになってますね。

VB.NET のメソッドの引数 ByVal, ByRef と、変数の値型, 参照型を区別して考え
てください。

まず、ByVal, ByRef ですが、

ByVal: 別の入れ物に中身をコピーして渡す
ByRef: 入れ物を中身ごと渡す(呼び出し側の入れ物は同じ)

次に値型・参照型ですが、

クラスや配列はあくまで参照型、構造体はあくまで値型で、ByVal, ByRef どちら
で渡そうと、参照型が値型に変わったり、値型が参照型に変わることはありません。

というわけで、以下の 4 つのケースを別々に考えてください。

(1) 値型を ByVal で渡す。

コピーなのでどのように操作しようと元の呼び出し側の変数には何の影響もない。

(2) 値型を ByRef で渡す

呼び出し側の入れ物とメソッドに渡された入れ物は同じなので、メソッド側で中身
を変更すれば呼び出し側でも中身が変更される。

(3) 参照型を ByVal で渡す。

渡されたのはコピーではあるが、参照型なので呼び出し側とメソッド側は同じオブ
ジェクト(インスタンス)を指している。なので、メソッド側でオブジェクトを変
更すると、呼び出し側でも同じ結果となる。

(4) 参照型を ByRef で渡す。

基本は (3) と同じ。ただし、呼び出し側の入れ物とメソッドに渡された入れ物は同
じなので、メソッド側で新しくインスタンスを生成してそれを入れ物に代入すると、
呼び出し元の入れ物が指すインスタンスもそれになる。

詳しくは以下の記事が参考になると思いますので読んでください。

値渡しと参照渡しの違いと使い分け
http://dobon.net/vb/dotnet/beginner/byvalbyref.html

値型と参照型については、以下の記事の図が分かりやすいと思いますので、

2-3 値型と参照型
https://msdn.microsoft.com/ja-jp/library/cc406735.aspx

値型と参照型の区別と違い クラスと構造体の違い
http://dobon.net/vb/dotnet/beginner/valuereference.html

引用返信 編集キー/
■83123 / inTopicNo.10)  Re[2]: byrefと参照の違いについて
□投稿者/ はーと (6回)-(2017/03/07(Tue) 12:06:45)
No83119 (Jitta さん) に返信
全く参考にならない
空気読めない?
引用返信 編集キー/
■83124 / inTopicNo.11)  Re[6]: byrefと参照の違いについて
□投稿者/ はーと (7回)-(2017/03/07(Tue) 12:14:15)
WebSurferさんに返信

中身はつまりtextboxですよね
考えてみます、ありがとうございます
引用返信 編集キー/
■83126 / inTopicNo.12)  Re[7]: byrefと参照の違いについて
□投稿者/ WebSurfer (1160回)-(2017/03/07(Tue) 13:48:33)
No83124 (はーと さん) に返信

どこまで理解されているのか分かりませんので少々くどい書き方になりますが・・・

> 中身はつまりtextboxですよね

参照型である TextBox クラスを例にとると、

Dim textbox AS TextBox

と宣言しただけでは textbox という入れ物が用意されただけです。「中身」はありませ
ん(しいて言えば「中身」は Nothing です)。

正確に言うと、textbox という変数名で、TextBox オブジェクトがどこにあるかを指すア
ドレス情報を保持するために必要なメモリが確保されただけです。

その後、

textbox = New TextBox()

とすると TextBox のオブジェクト(インスタンス)がメモリ上に生成以され、そのオブ
ジェクトのアドレス情報が textbox に代入されます。

その時点で「中身」は TextBox オブジェクトのアドレス情報になります。
引用返信 編集キー/
■83127 / inTopicNo.13)  Re[3]: byrefと参照の違いについて
□投稿者/ Jitta (278回)-(2017/03/07(Tue) 14:03:00)
No83123 (はーと さん) に返信
> ■No83119 (Jitta さん) に返信
> 全く参考にならない
> 空気読めない?

空気は、読みはしても、読んでもらう事を期待するものではありません。
全く異なる事柄を比較しようとしている時点でおかしい。
「質問」で済まそうとせず、ある程度まとまったお勉強をしてきましょう。
VBのインストールディレクトリに言語仕様があります。
引用返信 編集キー/
■83128 / inTopicNo.14)  Re[4]: byrefと参照の違いについて
□投稿者/ はーと (8回)-(2017/03/07(Tue) 14:16:18)
No83127 (Jitta さん) に返信
クソなマウンティング
クソマウント
引用返信 編集キー/
■83129 / inTopicNo.15)  Re[3]: byrefと参照の違いについて
□投稿者/ 774RR (479回)-(2017/03/07(Tue) 14:22:11)
下記、値型と参照型が理解できるまで ByVal ByRef はおいておいてよい。

値型と参照型の違いを C++er 的に解説するなら (ポインタが何か既に理解しているとして)

値型:そのまま値が格納できる型 int とか long とか
void foo(int x) { ... }
という関数を呼ぶと、関数の呼び出し手続きの際に「値の複写」がされるので、
呼ぶ側の渡した int と、呼ばれた側の int は別もの。
(呼び出された関数の中で x を変更しても、呼ぶ側に影響を [及ぼさない] [及ぼせない] )


参照型:ソースコード見た目に関係なく勝手にポインタになっている型
C# ソース上の TextBox t; や、
VB ソース上の Dim t As TextBox は、
C++ 的には TextBox* t=nullptr; と書いたのとほぼ同じ意味

ポインタだけあってもその指す先がないと役に立たないので
t=new TextBox(); のように new して「指す先」を正しく作る必要がある。

C#  コード void func(TextBox t) { ... } は
C++ コード void func(TextBox* t) { ... } と読むことができて
ここの t には「既にあるものを正しく指す」ように使う。
・呼ぶ側は「既に new TextBox 済みな何か」を渡す必要がある。
・呼ばれる側は、渡された「 new TextBox 済み」な既存の TextBox インスタンスを操作できる。
すなわち、呼ぶ側と呼ばれる側で「同一のもの」を操作することができる。
(呼び出された関数の中で、呼ぶ側が作ったブツの中身を変更できる)


引用返信 編集キー/
■83134 / inTopicNo.16)  Re[4]: byrefと参照の違いについて
□投稿者/ はーと (9回)-(2017/03/07(Tue) 17:42:40)
774RRさんに返信

たしかに型がよくわかってないので
ポインタなども考えてみます、ありがとうございます
引用返信 編集キー/
■83138 / inTopicNo.17)  Re[5]: byrefと参照の違いについて
□投稿者/ shu (971回)-(2017/03/07(Tue) 23:12:20)
No83128 (はーと さん) に返信

値型    ┌ a┬ b┐
     │ 5│ 7│
     └─┴─┘

参照型  ┌────────────┐     ┌ a┬ b┐
     │値の入っている場所(参照)│ →  │ 5│ 7│
          └────────────┘     └─┴─┘

これらの変数がcだとするとVB.NETやC#ではどちらでも
c.A, c.Bで読み出しを行い
c.A, c.Bで書き込みを行います。

変数cからdへの代入
d = c
を行った場合、
値型では値のコピーが作成されるためその時点では
同じもののように見えますがその後a,bの変更を行った場合
他方への影響が出ません。
参照型では参照のコピーをするためcもdも同じ中身となり
ますので片方を変更すると他方も変更されることになります。
値型のように扱うためには新たにインスタンスを作成して
中身をコピーする必要があります。

少ない領域で済むものは値型が適しており大きな領域が必要なものは
参照型が適しています。



ByVal ByRefについて
ByVal引数では値型であろうと参照型であろうとその値が渡されます。
つまり上記説明で示した代入と同じことが発生します。
ByRef引数では値型であろうと参照型であろうと渡した変数への参照が
わたされます。これによりその関数内での引数へのアクセスは渡した変数への
アクセスがおこなわれることになります。これは領域の大きな値型へのアクセスや
関数内で作成された値を元の変数に設定する場合に使われます。
値型であろうと参照型であろうと基本的に渡した変数への直接アクセスを行わなければ
ByVal、アクセスを行いたい場合はByRefを使うと考えればわかりやすいかと思います。

引用返信 編集キー/
■83166 / inTopicNo.18)  Re[6]: byrefと参照の違いについて
□投稿者/ はーと (10回)-(2017/03/09(Thu) 13:01:27)
shuさんに返信

矢印で書くとイメージが掴めそうです
ありがとうございます、自分でも書きます


WebSurferさんに返信

全部読んでます、ありがとうごいます
引用返信 編集キー/
■83167 / inTopicNo.19)  Re[7]: byrefと参照の違いについて
□投稿者/ はーと (11回)-(2017/03/09(Thu) 13:06:02)
自分の中でもやもやした物を
明確にします、書き込みいただいた
すべての皆様ありがとうございました!

引用返信 編集キー/
■83169 / inTopicNo.20)  Re[8]: byrefと参照の違いについて
 
□投稿者/ はーと (12回)-(2017/03/09(Thu) 13:07:54)
解決にします
解決済み
引用返信 編集キー/

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


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

このトピックに書きこむ