请考虑以下代码:
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
答案 0 :(得分:7)
您可以使用reflection设置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 Reflection Handbook 强>
反射是.NET提供的一种机制,使开发人员能够 使他们的程序更加灵活和动态。反思就是这样 应用程序可以更加模块化,可扩展,以及 可配置的。建立在面向对象和基于面向对象的基础上 .NET类型系统,反射提供动态机制 在运行时检查,修改甚至创建对象。 .NET也 增加了程序员向其类型添加属性的能力, 它提供了有关可以检查和使用的类型的元数据 通过运行时的反射。
本书探讨了反射可以使用的所有方法,并进行了识别 实际应用和依赖的重要编程技术 在反思他们的功能。它涵盖了反射API, 在.NET中使用属性,并查看.NET的机制 提供动态生成代码 - 所有允许的技术 开发人员构建更灵活,动态的应用程序。
答案 1 :(得分:3)
如果我正确理解了您的问题,您希望将temp(1)
的值分配给局部变量,其名称与temp(0)
的值相同。因此,如果您的文件包含S1=hello
,S2=world
,您希望代码将“hello”分配给变量S1
(以及“world”分配给变量S2
,如果这样的话变量存在)。
不幸的是,Visual Basic不支持将值分配给名称在运行时确定的局部变量。如果S1
是类字段或属性,则可以使用reflection或序列化库(例如XmlSerializer)来分配它,但是期望输入文件是XML格式而不是name = value对)。
一般而言,需要更多的背景来为您的情况提出最佳选择。例如,如果您只有S1
,...,S20
,我会使用array。如果您的密钥是任意名称,则Dictionary可能更合适。
答案 2 :(得分:3)
我希望我的问题是正确的。在我看来,好像你想将temp(1)
的值赋给你之前声明过的变量S1
。
这是通过简单的操作完成的:
S1 = temp(1)
或者,如果您不清楚,也可以使用Set
:
Set S1 = temp(1)
修改1
反思您刚刚撰写的对您的问题的评论,您要分割的字符串来自一个文件,该文件可能会在任何给定的时间点发生变化。
为此,我会考虑使用数据库(带触发器)或FileSystemWatcher
(文档here)对象来监视特定目录以进行文件更改。
使用此示例的示例解决方案如下所示。
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,它允许您在运行时评估代码,而不是编译-time。
我给了你一个示例代码,下面几乎总结了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)
答案 3 :(得分:2)
您无法反映出局部变量,因为在编译之后,编译器会丢失本地的名称,但会维护类级别的名称。
因此,为了使您的示例正常工作,您需要使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)
你必须记住的是,反思很昂贵。 除非你绝对必须这样做,否则不要这样做。在这种情况下,我看不到真正的需要,而且我没有看到任何让我说服你别无选择的东西。尝试尽可能简化您的解决方案。
答案 4 :(得分:2)
虽然您可以使用LocalVariables
类的Reflection.MethodBody
属性访问方法的局部变量,但是没有好的方法来设置值,因为变量名称不存储在任何地方。因此,您无法通过变量名称进行反射查找。你可以通过它们的索引/类型枚举局部变量,但没有明确的方法来判断哪个变量是哪一个,除了你事先知道它们被声明的确切顺序(在这种情况下你可以通过索引)。
您可以在这里找到有关我在msdn主题中所说内容的更多信息:
MethodBody.LocalVariables Property
如果您无论如何都需要通过反射查找局部变量,那么这是一个非常糟糕的设计,您应该在该部分工作更多(重构您的代码)。 你应该尽可能避免使用反射,因为它有很大的开销并且非常慢。 在你所处的情况下,Dictionary / SortedDictionary方法是一种更好的方法。
答案 5 :(得分:0)
如果将变量添加到变量的键控字典中,则可以使用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)
答案 6 :(得分:-2)
如果您只想将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")