0
Module MyModule
Public Property alpha As String
Public Property beta As String
Public Property charlie As String
End MyModule


Public Class MyClass
Sub New()
Dim variableName as String = "beta"
MyModule.GetField(variableName) = "new value"
End Sub
End Class

I'm looking for a way to set the value of a variable in the module. But only the variable with the given variable name. The example above obviously does not work, but it provides an idea of my goal.

Imports System.Reflection

Public Class Form1

    Sub New()
        SetVariableByVariableName("beta", "new value")
    End Sub

    Public Sub SetVariableByVariableName(ByVal variableName As String, ByVal value As String)
        Dim myFieldInfo As FieldInfo = GetType(MyModule).GetField(variableName, BindingFlags.Public Or BindingFlags.Static)
        If myFieldInfo IsNot Nothing Then
            myFieldInfo.SetValue(Nothing, value)
            Console.WriteLine($"The value of {variableName} is now: {GetType(MyModule).GetField(variableName).GetValue(Nothing)}")
        Else
            Console.WriteLine($"Error: {variableName} does not exist in MyModule.")
        End If
    End Sub

End Class


Module MyModule
    Public Property alpha As String
    Public Property beta As String
    Public Property charlie As String
End Module
Wabi-Sabi
  • 77
  • 6
  • I haven't tested but I think that you may be able to pass `Nothing`. Members of modules are effectively the same as `Shared` members of classes, so you would set a module field by Reflection in the same way you would set a `Shared` class field. I've never actually done that but I expect that you do it by passing no object to the first parameter of `SetValue`. – jmcilhinney Feb 15 '23 at 09:09
  • The documentation for that `SetValue` method says this: *"This method will assign value to the field reflected by this instance on object obj. If the field is static, obj will be ignored"*. `static` is the C# version of `Shared`. That seems to suggest that you pass absolutely anything as the first argument, but `Nothing` seems to be the obvious and sensible choice. – jmcilhinney Feb 15 '23 at 09:11

1 Answers1

1

Here's an example based on my previous answer here:

MyModule:

Module MyModule
    Public Property alpha As String
    Public Property beta As String = "default beta"
    Public Property charlie As String
End Module

Module1, which accesses the above "by name":

Imports System.Reflection
Module Module1

    Sub Main()
        Console.WriteLine("Module Property accessed directly: " & MyModule.beta)
        Console.WriteLine("Module Property accessed 'by name': " & GetModulePropertyByName("MyModule", "beta"))

        Console.WriteLine("Changing value...")
        SetModulePropertyByName("MyModule", "beta", "Can you hear me now?")

        Console.WriteLine("Module Property accessed directly: " & MyModule.beta)
        Console.WriteLine("Module Property accessed 'by name': " & GetModulePropertyByName("MyModule", "beta"))

        Console.WriteLine()
        Console.Write("Press any key to quit...")
        Console.ReadKey()
    End Sub

    Public Sub SetModulePropertyByName(ByVal moduleName As String, ByVal moduleField As String, ByVal value As String)
        Dim myType As Type = Nothing
        Dim myModule As [Module] = Nothing
        For Each x In Assembly.GetExecutingAssembly().GetModules
            For Each y In x.GetTypes
                If y.Name.ToUpper = moduleName.ToUpper Then
                    myType = y
                    Exit For
                End If
            Next
            If Not IsNothing(myType) Then
                Exit For
            End If
        Next
        If Not IsNothing(myType) Then
            Dim flags As BindingFlags = BindingFlags.IgnoreCase Or BindingFlags.NonPublic Or BindingFlags.Public Or BindingFlags.Static Or BindingFlags.Instance
            Dim pi As PropertyInfo = myType.GetProperty(moduleField, flags)
            If Not IsNothing(pi) Then
                pi.SetValue(Nothing, value)
            End If
        End If
    End Sub

    Public Function GetModulePropertyByName(ByVal moduleName As String, ByVal moduleField As String) As Object
        Dim O As Object = Nothing

        Dim myType As Type = Nothing
        Dim myModule As [Module] = Nothing
        For Each x In Assembly.GetExecutingAssembly().GetModules
            For Each y In x.GetTypes
                If y.Name.ToUpper = moduleName.ToUpper Then
                    myType = y
                    Exit For
                End If
            Next
            If Not IsNothing(myType) Then
                Exit For
            End If
        Next
        If Not IsNothing(myType) Then
            Dim flags As BindingFlags = BindingFlags.IgnoreCase Or BindingFlags.NonPublic Or BindingFlags.Public Or BindingFlags.Static Or BindingFlags.Instance
            Dim pi As PropertyInfo = myType.GetProperty(moduleField, flags)
            If Not IsNothing(pi) Then
                O = pi.GetValue(Nothing)
            End If
        End If

        Return O
    End Function

End Module

Output:

Module Property accessed directly: default beta
Module Property accessed 'by name': default beta
Changing value...
Module Property accessed directly: Can you hear me now?
Module Property accessed 'by name': Can you hear me now?

Press any key to quit...
Idle_Mind
  • 38,363
  • 3
  • 29
  • 40