簡體   English   中英

如何使用VB.NET為字符串賦值?

[英]How to assign value to string using VB.NET?

考慮以下代碼:

    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?

我已經聲明了一個名為S1的字符串。 現在我想為S1分配新值。 新字符串值使用以下格式存儲在文件中: [變量名稱] [=作為分隔符] [字符串值] 在檢索存儲在文件中的字符串變量名稱和值后,如何將值分配給S1?

注意:

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

應該注意的是,帶有數據的字符串來自一個可能會不時變化的文件! 當文件發生變化時,我也希望變量也能改變。

進一步澄清

我需要一段代碼,當處理像“S1 = hello”這樣的字符串時,代碼將首先找到一個聲明的變量(即S1),然后為S1變量分配“hello”字符串。 “=”僅作為變量名和變量值的分隔符。

更新

我嘗試使用Mathias Lykkegaard Lorenzen的EDIT 2示例但在此行"Field.SetValue(Me, VariableValue)"使用“NullReferenceException”失敗。 請幫我解決問題。 以下是基於Mathias Lykkegaard Lorenzen的EDIT 2示例的代碼:

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

您可以使用反射來設置S1值:

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

額外資源

有一本關於反思的書非常好,請看一下:

Visual Basic .NET反射手冊

反射是.NET提供的一種機制,使開發人員能夠使他們的程序更加靈活和動態。 反射使應用程序可以更加模塊化,可擴展和可配置。 基於面向對象和.NET類型系統的基礎,反射提供了在運行時動態檢查,修改甚至創建對象的機制。 .NET還增加了程序員向其類型添加屬性的能力,這些屬性提供了有關可在運行時通過反射檢查和使用的類型的元數據。

本書探討了反射可以使用的所有方法,並確定了依賴於反射功能的實際應用和重要的編程技術。 它涵蓋了反射API,.NET中屬性的使用,還介紹了.NET為動態生成代碼提供的機制 - 所有這些技術都允許開發人員構建更靈活,動態的應用程序。

如果我正確理解了您的問題,您希望將temp(1)的值賦給local變量,其名稱與temp(0)的值相同。 因此,如果您的文件包含S1=helloS2=world ,您希望代碼將“hello”分配給變量S1 (如果存在這樣的變量,則將“world”分配給變量S2 )。

遺憾的是,Visual Basic不支持將值分配給名稱在運行時確定的局部變量。 如果S1是類字段或屬性,則可以使用反射或序列化庫(例如XmlSerializer ,但它希望輸入文件是XML格式而不是名稱=值對)來分配它。

一般而言,需要更多的背景來為您的情況提出最佳選擇。 例如,如果你只有名字S1 ,..., S20 ,我會使用一個數組 如果您的鍵是任意名稱,則詞典可能更合適。

我希望我的問題是正確的。 在我看來,好像你想將temp(1)的值賦給你之前聲明的變量S1

這是通過一個簡單的操作完成的:

S1 = temp(1)

或者,如果您不清楚,也可以使用Set

Set S1 = temp(1)

有關此處此處的更多信息。

編輯1

反映您剛才寫的對您的問題的評論,您要分割的字符串來自一個文件,該文件可能在任何給定的時間點發生變化。

為此,我會考慮使用數據庫(帶觸發器)或FileSystemWatcher此處的文檔)對象來監視特定目錄的文件更改。

使用它的樣品溶液如下所示。

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

然后,在您的事件處理程序中:

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 

編輯2

如果您希望能夠將給定該變量名稱的變量值更改為string ,那么您應該查看Reflection,它允許您在運行時評估代碼,而不是編譯時。

我給了你一個示例代碼,下面幾乎總結了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)

您無法反映出局部變量,因為在編譯之后,編譯器會丟失本地的名稱,但會為類級別的名稱維護名稱。

因此,為了使您的示例有效,您需要使S1成為類級變量,而不是將其作為方法的內部變量。

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

然而,正如這里已經說過的,更實用的方法是使用字典。

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

如果你有一個字典已經有你在其中的值,你當然不會做一個添加,你只需要將鍵設置為新值,如test(temp(0)) = temp(1)


你要記住的是,反射是昂貴的。 除非你絕對必須這樣做,否則不要這樣做。 在這種情況下,我無法看到它的真正需要,我沒有看到任何讓我說服你別無選擇的東西。 盡量保持您的解決方案盡可能簡單。

雖然您可以使用Reflection.MethodBody類的LocalVariables屬性訪問方法的局部變量,但是沒有好的方法來設置值,因為變量名稱不會存儲在任何位置。 因此,您無法通過變量名稱進行反射查找。 你可以通過它們的索引/類型枚舉局部變量,但沒有明確的方法來判斷哪個變量是哪一個,除了你事先知道它們被聲明的確切順序(在這種情況下你可以通過索引)。

您可以在這里找到有關我在msdn主題中所說內容的更多信息:

MethodBody.LocalVariables屬性

如果您無論如何都需要通過反射查找局部變量,那么這是一個非常糟糕的設計,您應該在該部分上更多地工作(重構您的代碼)。 你應該盡可能避免使用反射,因為它有很大的開銷並且非常慢。 Dictionary / SortedDictionary方法是一種更好的方式來處理你所處的情況。

如果將變量添加到變量的鍵控字典中,則可以使用set來設置鍵值對中的值的值。 看一下這個:

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)

如果您只想將temp(1)的值賦給S1 ,則可以這樣做:

S1 = temp(1)

如果您有一組固定的小的可能值,則可以嘗試使用Select Case

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

但一般來說,最好的方法是使用字典來保存值,而不是變量:

Dim dict = New Dictionary(Of String, String)

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

然后,您可以通過以下方式獲取S1的值:

dict("S1")

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM