PropertyInfo.SetValue 在 属性 列表(Of Int32)上

PropertyInfo.SetValue on a property List(Of Int32)

我有一个 Class 有一些像这样的列表属性:

Public Class ListPropertiesClass
    Public Property Id As List(Of Int32)
End Class

另一个 class 我使用反射的地方:

Public Class Test

   Public Sub MySub()

      Dim IdentityValue as Int32 = 100
      Dim PropertyName as String = "Id"
      Dim LPC as new ListPropertiesClass
      Dim pInfo As PropertyInfo

      pInfo = LPC.GetType().GetProperty(PropertyName)
      If Not pInfo Is Nothing Then

          pInfo.SetValue(LPC, Convert.ToInt32(IdentityValue), Nothing)

       End If

   End Sub

End Class

但是当我尝试使用它时它不起作用,因为我试图将 Int32 类型的值设置为 List one,我如何使用 PropertyInfo.SetValue 添加 List Itens?添加后如何使用反射获取列表的特定索引的值

pInfo.GetValue(LPC, Nothing)

如果有人能帮助我,我会很高兴。谢谢。

您必须首先获取当前 属性 的值(并检查它),如下所示

这是示例,因为我不记得 vb.net

的确切语法
Dim pValue = pInfo.GetValue(LPC, Nothing)
Dim castedValue As List(Of Integer) = TryCast(pValue, List(Of Integer))

If castedValue Is Nothing Then
   castedValue = New List(Of Integer)()
End If
castedValue.Add(IdentityValue)
pInfo.SetValue(LPC, Convert.ToInt32(IdentityValue), Nothing)
  • 首先,正如您已经指出的,您不能将 Int32 值分配给 List(Of Int32) 属性.

  • 其次,我不确定你到底想完成什么,但我会同意 - 让我们分配一个 newly created List(Of Int32) 实例对 属性 的引用,使用

这里什么都没有:

Dim newList As New List(Of Int32)
pInfo.SetValue(LPC, newList, Nothing)

现在,您可以向列表中添加内容(您已经有对它的引用):

Dim newList As New List(Of Int32)
pInfo.SetValue(LPC, newList, Nothing)

newList.Add(10)
newList.Add(11);

存储列表的不是属性。 属性 存储一个引用(一个 4 字节 = 32 位长的数值)。 引用、指针或地址不是实际实例。

您使用引用对实例执行操作,并且您可以对同一实例有多个引用。

视角的改变

假设您对像我刚才那样使用 Reflection 不感兴趣。假设您同意以下修改:

Public Class ListPropertiesClass
    Public Property Id As List(Of Int32)

    Sub New()
        Property = New List(Of Int32)
    End Sub
End Class

基本上,每个 ListPropertiesClass 实例都需要一个 List(Of Int32) 实例,这是一件微不足道的事情,所以让我们简单地创建 List(Of Int32) 及其包装器 - 这里没有反映.

现在,假设您想使用反射向该列表添加 Int32 个值。

首先看看在没有反射的情况下如何实现:

LPC.Property.Add(10)     ' LINE 1

可以翻译成这个等效代码:

Dim theList As List(Of Int32)     ' LINE 2
theList = LPC.Property            ' LINE 3
theList.Add(10)                   ' LINE 4

如果您不能完全确定最后 3 行与用 ' LINE 1 注释的行具有完全相同的效果,那么我建议您复习一下 类、实例和参考资料通用 OOP。

现在,让我们看看最后 3 行实际上在做什么(还没有使用反射):

  • ' LINE 2只是一个变量声明
  • ' LINE 3 是一个 get 操作后跟一个赋值
  • ' LINE 4是方法的调用

所以,这里的关键方面是 ' LINE 3get 而不是 set.

现在你要做的是:

我们将声明一个可以存储 Object 个引用的变量,而不是声明一个可以存储 List(Of Int32) 个引用的变量

' so this line
' Dim theList as List(Of Int32)
' becomes this line
Dim theList As Object

而不是 "getting in a regular fashion" 并将 属性 的值赋给变量,我们仍然进行赋值,但我们使用反射

获取值
' so this line
' theList = LPC.Property
' becomes this line
theList = LPC.GetType().GetProperty(PropertyName).GetValue(LPC, Nothing)

(注意后面的 GetValue 调用)

不是使用指向 List(Of Int32) 实例的 List(Of Int32) 引用简单地将值添加到列表中,而是使用 Object 调用 Add 方法指向的参考 - 你猜对了 - List(Of Int32) 实例

' so this line
' theList.Add(10)
' becomes this line
theList.GetType().GetMethod("Add").Invoke(theList, New Object() { 10 })

注意 Invoke 方法。单击 link 获取有关它的 msdn 文章。

总结起来,它应该看起来像这样:

Dim theList As Object
theList = LPC.GetType().GetProperty(PropertyName).GetValue(LPC, Nothing)
theList.GetType().GetMethod("Add").Invoke(theList, New Object() { 10 })

现在您可以满足于简单地将 Object 引用转换为 List(Of Int32) 引用并调用 Add 方法 而无需 反射。在这种情况下,局部变量可以是 List(Of Int32):

Dim theList As List(Of Int32)
theList = TryCast(LPC.GetType().GetProperty(PropertyName).GetValue(LPC, Nothing), List(Of Integer))
theList.Add(10)

祝你好运!