How can I get ByRef Arguments to work in a dynamically created assembly with Method.Invoke

127 views Asked by At

I have a text file that I am compiling into an assembly use the VBCodeProvider class

The file looks like this:

Imports System
Imports System.Data
Imports System.Windows.Forms

Class Script

    Public Sub AfterClockIn(ByVal clockNo As Integer, ByRef comment As String)
        If clockNo = 1234 Then
            comment = "Not allowed"
            MessageBox.Show(comment)
        End If
    End Sub

End Class

Here is the compile code:

Private _scriptClass As Object
Private _scriptClassType As Type

Dim codeProvider As New Microsoft.VisualBasic.VBCodeProvider()
Dim optParams As New CompilerParameters
optParams.CompilerOptions = "/t:library"
optParams.GenerateInMemory = True
Dim results As CompilerResults = codeProvider.CompileAssemblyFromSource(optParams, code.ToString)
Dim assy As System.Reflection.Assembly = results.CompiledAssembly
_scriptClass = assy.CreateInstance("Script")
_scriptClassType = _scriptClass.GetType

What I want to do is to modify the value of the comment String inside the method, so that after I call it from code I can inspect the value:

Dim comment As String = "Foo"
Dim method As MethodInfo = _scriptClassType.GetMethod("AfterClockIn")
method.Invoke(_scriptClass, New Object() {1234, comment})
Debug.WriteLine(comment)

However comment is always "Foo" (message box shows "Not Allowed"), so it appears that the ByRef modifier is not working

If I use the same method in my code comment is correctly modified.

1

There are 1 answers

3
Jon Skeet On BEST ANSWER

However comment is always "Foo" (message box shows "Not Allowed"), so it appears that the ByRef modifier is not working

It is, but you're using it incorrectly, with incorrect expectations :)

When you create the argument array, you're copying the value of comment into the array. After the method has completed, you no longer have access to the array, so you can't see that it's changed. That change in the array won't affect the value of comment, but demonstrates the ByRef nature. So what you want is:

Dim arguments As Object() = New Object() { 1234, comment }
method.Invoke(_scriptClass, arguments)
Debug.WriteLine(arguments(1))