2011-12-02 1 views
5

リストの列挙子を関数 "byval"に渡すのは、 "byref"を渡すのとは全く違っているようです。基本的に、関数が列挙子を進める場合でも、通常の "byval"の引き渡しは、呼び出し元の "列挙子。現在の値"を変更しません。なぜ誰がこの事件の原因を知っているのだろうかと思っていたのですか?列挙子はオブジェクト参照なしで整数のようなプリミティブなので、それに対する変更は呼び出し元に反映されませんか?ここでリストの列挙子を関数に渡す

はサンプルコードです:

列挙子の「現在」は過去5を前進させることがないので、この機能は、BYVALあり、そして無限ループで立ち往生、「1」のメッセージボックスを吐き出し:

Public Sub listItemsUsingByValFunction() 
    Dim list As New List(Of Integer)(New Integer() {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) 

    Dim enumerator = list.GetEnumerator() 
    enumerator.MoveNext() 
    While enumerator.Current <= 5 
     listFirstItemByVal(enumerator) 
    End While 
End Sub 
Private Sub listFirstItemByVal(ByVal enumerator As List(Of Integer).Enumerator) 
    MsgBox(enumerator.Current) 
    enumerator.MoveNext() 
End Sub 

これ、一方、1が期待するのと同じように動作します:

Public Sub listItemsUsingByRefFunction() 
    Dim list As New List(Of Integer)(New Integer() {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) 

    Dim enumerator = list.GetEnumerator() 
    enumerator.MoveNext() 
    While enumerator.Current <= 5 
     listFirstItemByRef(enumerator) 
    End While 
End Sub 
Private Sub listFirstItemByRef(ByRef enumerator As List(Of Integer).Enumerator) 
    MsgBox(enumerator.Current) 
    enumerator.MoveNext() 
End Sub 

二つの関数の違いはlistFirstItem__機能が受け入れるかどうかだけですbyvalまたはbyref列挙子です。

答えて

8

この現象が表示される理由は、List(Of T).EnumeratorStructであり、一般的にはClassではありません。したがって列挙子を渡すと、そのコピーを渡すので、呼び出すときにそのコピーのみが更新されますMoveNext

+0

面白い!これを明確にしていただきありがとうございます! –

+0

したがって、列挙子を関数に渡すと、「byref」を使用するために常にメンタルノートを作成しますか?たとえば、Visual Studioは常にbyvalを使用するメソッドを自動的に生成するため、これを常に覚えておく必要を回避するための回避策がいくつかあります。そのようなことは気付かれにくいでしょうか? –

+0

@MichaelZlatkovsky最も一般的なケースであるIEnumerator(Of T)を使用する場合、これを行う必要はありません。型固有の列挙子を渡すたびに、常にByValとByRefを実行する前に型をチェックします。 – JaredPar

0

提供されているサンプルコードを使用すると、Option Strict Onを使用してコンパイルされません。あなたが見る違いを修正するかもしれない修正。

Public Sub listItemsUsingByValFunction() 
    Dim list As New List(Of Integer)(New Integer() {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) 

    Dim enumerator As IEnumerator(Of Integer) = list.GetEnumerator() 
    enumerator.MoveNext() 
    Debug.WriteLine("S " & enumerator.Current) 
    Stop 
    Do 
     Debug.WriteLine("W " & enumerator.Current) 
     If Not listFirstItemByVal(enumerator) Then Exit Do 
    Loop 
End Sub 

Private Function listFirstItemByVal(ByVal enumerator As IEnumerator(Of Integer)) As Boolean 
    Debug.WriteLine("F " & enumerator.Current) 
    Return enumerator.MoveNext() 
End Function 

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click 
    listItemsUsingByValFunction() 
End Sub 
+0

本当ですか?オリジナルのコードに "Option Strict On"を追加しましたが、警告やエラーは表示されません。 –

+1

私は、Option Strict On、Option Infer Off、Option Explicit Onと言っていたはずです。ごめんなさい。 – dbasnett

+0

ええ、私は、推論をオフにすると別の方法では表示されていないエラーが発生することに気づいていませんでした(プロジェクトを最初にセットアップしたときに、より多くのものが "オン"あなたの意見ではベストプラクティスですか?かなりタイピングが必要ないのですか?たとえば、それはあなたにとって価値がありますか? –