简体   繁体   中英

How to assign value to string using VB.NET?

Consider following code:

    Dim S1 As String = "a"

    'this is the string in a file
    Dim StringFromFile As String = "S1=hello"

    Dim temp() As String = Split(StringFromFile, "=", -1, CompareMethod.Binary)
    'temp(0) = variable name
    'temp(1) = variable value

    'my question is: how to assign value to S1?

I have declared a string named S1. Now I want to assign new value to S1. The new string value is stored in a file using following format: [variable name][= as separator][string value] . How do I assign the value to S1 after retrieving the string variable name and value that stored in a file?

NOTE:

temp(0) = "S1"
temp(1) = "hello"

It should be noted that the string with the data comes from a file that may change from time to time! When the file changes, I want the variables to change as well.

Further clarification

I need a piece of code that when processing a string like this "S1=hello", the code will first find a declared variable (ie S1), and then assign the S1 variable with "hello" string. The "=" just acted as separator for variable name and variable value.

UPDATE :

My attempt to use Mathias Lykkegaard Lorenzen's EDIT 2 example but failed with "NullReferenceException" on this line "Field.SetValue(Me, VariableValue)" . Please help me fix the problem. Following is my code based on Mathias Lykkegaard Lorenzen's EDIT 2 example:

Public Sub Ask()
    Try
        Dim S1 As String = "a"

        Dim StringFromFile As String = "S1=hello"

        Dim temp() As String = Split(StringFromFile, "=", -1, CompareMethod.Binary)
        'temp(0) = variable name
        'temp(1) = variable value

        'my question is: how to assign value to S1?
        Dim TypeOfMe As Type = Me.GetType()

        'did this for readability.
        Dim VariableName As String = temp(0)
        Dim VariableValue As String = temp(1)

        'get the field in the class which is private, given the specific name (VariableName).
        Dim Field As FieldInfo = TypeOfMe.GetField(VariableName, BindingFlags.NonPublic Or BindingFlags.Instance)

        'set the value of that field, on the object "Me".
        Field.SetValue(Me, VariableValue) '<-- this line caused NullReferenceException
        MessageBox.Show(S1)
    Catch ex As Exception
        MessageBox.Show(ex.ToString)
    End Try

End Sub

You can use reflection to set S1 value:

Imports System.Reflection

Public Class Form1
    Public S1 As String = "a"

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Dim StringFromFile As String = "S1=hello"

        Dim temp() As String = Split(StringFromFile, "=", -1, CompareMethod.Binary)
        'temp(0) = variable name
        'temp(1) = variable value

        SetS1(Me, "S1", temp(1))
        MessageBox.Show(S1)
    End Sub

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="obj">the class that stores your S1 public field</param>
    ''' <param name="fieldName">that is your S1 field</param>
    ''' <param name="Value">S1 new value, that is hello</param>
    ''' <remarks></remarks>
    Public Sub SetS1(ByVal obj As Object, ByVal fieldName As String, ByVal Value As Object)
        Try
            Dim fi As FieldInfo = obj.GetType().GetField(fieldName, BindingFlags.Instance Or BindingFlags.Public Or BindingFlags.NonPublic)
            If Not fi Is Nothing Then
                fi.SetValue(obj, Value)
            End If

        Catch ex As Exception

        End Try
    End Sub
End Class

Additional resource

There is a book about reflection which is very good, take a look:

Visual Basic .NET Reflection Handbook

Reflection is a mechanism provided by .NET that enables developers to make their programs more flexible and dynamic. Reflection makes it possible for applications to be more modular, extensible, and configurable. Building on the basics of object-orientation and the .NET type system, reflection provides mechanisms for dynamically examining, modifying, and even creating objects at run time. .NET also adds the ability for programmers to add attributes to their types, which provide metadata about the type which can be examined and used through reflection at runtime.

This book examines all the ways reflection can be used, and identifies practical applications and important programming techniques that rely upon reflection for their functionality. It covers the reflection API, the use of attributes in .NET, and also looks at the mechanisms .NET provides for dynamic generation of code - all techniques that allow developers to build more flexible, dynamic applications.

If I understood your question correctly, you want to assign the value of temp(1) to the local variable with the same name as the value of temp(0) . So, if your file contains S1=hello , S2=world , you want your code to assign "hello" to variable S1 (and "world" to variable S2 , if such a variable exists).

Unfortunately, Visual Basic does not support assigning values to local variables whose names are determined at run-time. If S1 were a class field or property, you could assign it using reflection or a serialization library (eg XmlSerializer , which however expects input files to be in XML format rather than name=value pairs).

In general, a bit more context would be needed to suggest the best alternative for your situation. For example, if you just have names S1 , ..., S20 , I'd use an array . If your keys are arbitrary names, a Dictionary might be more appropriate.

I hope I am getting the question right. It seems to me as if you want to assign the value of temp(1) to the variable S1 which you have declared earlier.

This is done using a simple operation:

S1 = temp(1)

Or if that is not clear for you, Set can be used as well:

Set S1 = temp(1)

More information on that here and here .

Edit 1

Reflecting on what you just wrote as a comment to your question, the string that you are splitting comes from a file which may change at any given point in time.

For that, I would consider using either a database (with triggers), or a FileSystemWatcher (documentation here ) object to monitor a specific directory for file changes.

A sample solution using this is shown below.

Dim watcher As New System.IO.FileSystemWatcher()
watcher.Path = "C:\MyPathToMonitor"
watcher.Filter = "*MyFileNameToLookFor" 'could be *MyFile.txt

'assign the event. could be done by declaring the watcher `WithEvents` in the class scope too.
AddHandler watcher.Changed, AddressOf OnChanged

And then, in your event handler:

Private Shared Sub OnChanged(source As Object, e As FileSystemEventArgs)

    'here we just say that StringFromFile has been assigned to the file contents now.

    Dim temp() As String = Split(StringFromFile, "=", -1, CompareMethod.Binary)

    'remember to have the S1 variable in your class scope.
    S1 = temp(1)

End Sub 

Edit 2

If you want to be able to change the value of a variable given the name of that variable as a string , then you should look into Reflection, which allows you to evaluate code at runtime, as opposed to compile-time.

I gave you a sample code below which pretty much sums up the use of Reflection.

'get the reflection type of the current class.
Dim TypeOfMe As Type = Me.GetType()

'did this for readability.
Dim VariableName = temp(0)
Dim VariableValue = temp(1)

'get the field in the class which is private, given the specific name (VariableName).
Dim Field As FieldInfo = TypeOfMe.GetField(VariableName, BindingFlags.NonPublic Or BindingFlags.Instance)

'set the value of that field, on the object "Me".
Field.SetValue(Me, VariableValue)

You can't reflect out a local variable because after compilation, the compiler loses the names of locals, but maintains names for those at class level.

So to make your example work, you need to make S1 a class level variable, not have it as an internal variable to the method.

Public Class Class1
    Dim S1 As String = "a"

    Public Sub Ask()
        Try
            Dim StringFromFile As String = "S1=hello"

            Dim temp() As String = Split(StringFromFile, "=", - 1, CompareMethod.Binary)
            'temp(0) = variable name
            'temp(1) = variable value

            'my question is: how to assign value to S1?
            Dim TypeOfMe As Type = Me.GetType()

            'did this for readability.
            Dim VariableName As String = temp(0)
            Dim VariableValue As String = temp(1)

            'get the field in the class which is private, given the specific name (VariableName).
            Dim Field As FieldInfo = TypeOfMe.GetField(VariableName, BindingFlags.NonPublic Or BindingFlags.Instance)

            'set the value of that field, on the object "Me".
            Field.SetValue(Me, VariableValue)            '<-- this line caused NullReferenceException (no more.)
            Console.WriteLine("S1 using reflection")
            Console.WriteLine(S1)

        Catch ex As Exception
            Console.WriteLine(ex.ToString)
        End Try
    End Sub
End Class

However, as has already been said here, a much more pragmatic approach is to use a dictionary.

Public Class Class2

    Public Sub Ask()
        Try
            Dim StringFromFile As String = "S1=hello"

            Dim temp() As String = Split(StringFromFile, "=", - 1, CompareMethod.Binary)

            ' the way you probably should do it.
            Dim test As Dictionary(Of string, string) = New Dictionary(Of String,String)()
            test.Add(temp(0), temp(1))
            Console.WriteLine("S1 using dictionary")
            Console.WriteLine(test("S1"))

        Catch ex As Exception
            Console.WriteLine(ex.ToString)
        End Try
    End Sub
End Class

if you had a dictionary that already had the values you were after in it, you wouldn't be doing an add of course, you would just be setting the key to the new value like test(temp(0)) = temp(1)


What you have to remember is that Reflection is expensive. Don't do it unless you absolutely have to. In this instance, I can't see the real need for it, and I've seen nothing to convince me you have no other choice. Try and keep your solution as simple as possible.

While you can get access to the Local Variables of a method using the LocalVariables Property of the Reflection.MethodBody class, there is no good way to set the values, because the variable names are not stored anywhere. So you can't lookup via reflection by variable names. You can enumerate the local variables by their index/type, but there is no definitive way to tell which variable is which one, except that you know beforehand the exact sequence in which they are declared (in which case you can go by index).

You can find more information about what I'm saying in the msdn topic here:

MethodBody.LocalVariables Property

If you are anyways needing to lookup local variables via reflection, then it is an utterly bad design and you should work more on that part (refactoring your code). You should avoid using reflection altogether wherever possible, because it has large overheads and is extremely slow. The Dictionary/SortedDictionary approach is a much better way to go in the situation you are in.

If you add your variables to a keyed dictionary of variables, you can use set to set the value of the value in the Key Value pair. Check this out:

Dim dctHolder As New Dictionary(Of String, Object)
Dim S1 As String
Dim tmp() As String = {"S1","Split Up Value"}
dctHolder.Add("S1",S1)
Set dctHolder(tmp(0)) = tmp(1)

If you only want to assign the value of temp(1) to S1 , you can do that:

S1 = temp(1)

If you have a small, fixed set of possible values, you could try to use Select Case :

Select Case temp(0)
    Case "S1"
        S1 = temp(1)
    Case "S2"
        S2 = temp(1)
End Select

But generally, the best way to do this is to use a dictionary to hold the values, not variables:

Dim dict = New Dictionary(Of String, String)

dict(temp(0)) = temp(1)

You can then get the value of S1 by something like:

dict("S1")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM