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

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

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

Re[4]: 引数に配列を使う場合のByValとByRefについて


(過去ログ 104 を表示中)

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

■61866 / inTopicNo.1)  引数に配列を使う場合のByValとByRefについて
  
□投稿者/ kei (10回)-(2011/09/09(Fri) 13:42:55)

分類:[.NET 全般] 

関数に渡す配列について質問があります。

関数に配列を渡す場合、ByRefでしか渡せないとテキストに書いてあったのですが
ByValで引数を渡すプログラムを作ってもコンパイルエラーにはなりませんでした。

また、ByValで渡しても関数内部で配列の値を入れるとByRefと同じ動作をして
渡した配列の値が変えられてしまいました。


どうやら関数に配列を渡すとき、ByValでも強制的にByRefに作り替えられてしまうようだなと
思っているのですが、実際にそうなのでしょうか?


何か知っている方がいらっしゃいましたら、よろしくお願いいたします。


環境
OS:WindowsXP
開発:Visual Studio 2010 Express
言語:VB.NET
引用返信 編集キー/
■61869 / inTopicNo.2)  Re[1]: 引数に配列を使う場合のByValとByRefについて
□投稿者/ shu (981回)-(2011/09/09(Fri) 14:06:10)
No61866 (kei さん) に返信

Private Sub ByValAry(ByVal ary() As Integer)
ary = {4, 5, 6}
End Sub

Private Sub ByRefAry(ByRef ary() As Integer)
ary = {4, 5, 6}
End Sub

・・・・

Dim a = {1, 2, 3}
ByValAry(a)
Console.WriteLine("{0},{1},{2}", a(0), a(1), a(2))
ByRefAry(a)
Console.WriteLine("{0},{1},{2}", a(0), a(1), a(2))


結果:
1,2,3
4,5,6

引用返信 編集キー/
■61870 / inTopicNo.3)  Re[1]: 引数に配列を使う場合のByValとByRefについて
□投稿者/ Hongliang (803回)-(2011/09/09(Fri) 14:10:29)
> 関数に配列を渡す場合、ByRefでしか渡せないとテキストに書いてあったのですが
そのテキストは対象が VB6 かそれ以前、あるいは VBA に向けて書かれたものではないでしょうか。
VB.NET 以降とは文法が似ているだけの別言語と考えて良いので、参考にはしない方が良いと思います。

> また、ByValで渡しても関数内部で配列の値を入れるとByRefと同じ動作をして
> 渡した配列の値が変えられてしまいました。
> どうやら関数に配列を渡すとき、ByValでも強制的にByRefに作り替えられてしまうようだなと
> 思っているのですが、実際にそうなのでしょうか?
配列は参照型のオブジェクトなので、実体は一つだけであり、メソッドの引数にした場合も配列の場所(参照)だけコピーして渡され、配列の実体はコピーされません。
ですので、ByRef / ByVal のいずれで渡しても、要素を書き換えれば、ただ一つの実体の内容が書き換えられます。
参照型における ByRef / ByVal の違いは以下のようなサンプルで分かります。

Dim a(4) As Integer
FuncByVal(a)
System.Diagnostics.Debug.Print(a.Length.ToString())
FuncByRef(a)
System.Diagnostics.Debug.Print(a.Length.ToString())

Shared Sub FuncByVal(ByVal a As Integer())
a = New Integer(1) { }
End Sub
Shared Sub FuncByRef(ByRef a As Integer())
a = New Integer(10) { }
End Sub
引用返信 編集キー/
■61884 / inTopicNo.4)  Re[2]: 引数に配列を使う場合のByValとByRefについて
□投稿者/ kei (11回)-(2011/09/09(Fri) 22:44:54)
shuさん、Hongliangさん、ありがとうございます。

今読んでいる本は、技術評論社の川西朝雄著のVB.NET基礎学習BIBLEという本で
247ページ目に配列データはByRefによる参照渡しで行う、と書かれていました。

お二人が書かれたサンプルを実行してみると、確かにその通りの結果になったのですが
自分で試したコードと結果が違いました。

Private Sub FuncVal(ByVal a As Integer())
a(0) = 10
a(1) = 20
End Sub

Private Sub FuncRef(ByRef a As Integer())
a(0) = 50
a(1) = 60
End Sub

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim a(1) As Integer

a(0) = 1
a(1) = 2

FuncVal(a)
System.Diagnostics.Debug.Print(a(0))
System.Diagnostics.Debug.Print(a(1))

    FuncRef(a)
System.Diagnostics.Debug.Print(a(0))
System.Diagnostics.Debug.Print(a(1))
End Sub

このようなコードを書いたのですが、結果は

10
20
50
60

このような結果になりました。ByRef、ByValもどちらも同じような動きをしました。
a(1)などでインデックスまで指定している場合はこのような動きになるのでしょうか?

shuさん、Hongliangさんのコードだと、ByValで渡したときは影響は無かったのですが私のと
明らかに動作が違うように思われます。
私のコードのどこに違いがあるのでしょうか。
引用返信 編集キー/
■61886 / inTopicNo.5)  Re[3]: 引数に配列を使う場合のByValとByRefについて
□投稿者/ shu (982回)-(2011/09/10(Sat) 00:11:16)
No61884 (kei さん) に返信

> shuさん、Hongliangさんのコードだと、ByValで渡したときは影響は無かったのですが私のと
> 明らかに動作が違うように思われます。
> 私のコードのどこに違いがあるのでしょうか。
インデックス指定して配列の一部を書き換えているのと、配列の代入自体を行っているという違いです。

参照型だとByRefでもByValでも中身のコピーはされません。ByRefの場合、引数自体の書き換えをすると元の
変数のなかも書き換わります。
配列においては参照型なのでコピーはされません。なので引数自体の書き換えをしない限り
ByValとByRefの動作は同じになります。
参照型でも値型でもByRefを使うのはFunction, Sub内で処理し作成されたものをその引数を通して受け取る場合に
使用します。構造体は値型なので大きい構造体を渡す場合はByRefの方がよいですがそういう場合は構造体ではなく
クラスにした方が効率が良くなることが多いです。ByRef渡しを処理効率の為に使用するのは.Netではほぼありません。
引用返信 編集キー/
■61903 / inTopicNo.6)  Re[4]: 引数に配列を使う場合のByValとByRefについて
□投稿者/ kei (12回)-(2011/09/11(Sun) 15:46:47)
shuさん。

ありがとうございました。
ByRef、ByValだけではなく、代入の仕方にも影響があるんですね。

気をつけてコーディングをしていこうと思います。
解決済み
引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -