You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VB中PropertyInfo.SetValue对值类型结构体失效问题及解决方法

解决VB中通过反射修改值类型(Size)属性无效的问题

问题背景

在VB中尝试通过PropertyInfo.SetValue修改值类型(如System.Drawing.Size结构体)的属性时,即便执行了装箱操作,属性值依然无法被修改;但相同逻辑的C#代码却能正常生效。

原因分析

VB与C#在处理装箱值类型的反射调用时存在语义差异:

  • C#:将值类型装箱到Object变量后,传递给PropertyInfo.SetValue的是装箱实例的引用,修改操作直接作用于该实例,因此能看到属性变化。
  • VB:当把装箱的Object变量传递给PropertyInfo.SetValue时,编译器会自动执行「拆箱为值类型→重新装箱」的操作,导致修改作用于临时创建的装箱实例,原Object变量引用的实例并未被改动,所以属性值无变化。

解决方案

以下两种方式均可在VB中实现预期效果:

方法1:使用Type.InvokeMember替代PropertyInfo.SetValue

直接调用Type.InvokeMember方法,指定SetProperty绑定标志,确保操作作用于原装箱实例:

Imports System.Drawing
Imports System.Reflection

Module Module1
    Sub Main()
        Console.WriteLine("Starting test")
        Dim s As Size
        Console.WriteLine("Created size: {0}", s)
        s.Width = 5
        Console.WriteLine("Set Width: {0}", s)
        
        Dim sizeType = s.GetType()
        Dim pi = sizeType.GetProperty("Height")
        Console.WriteLine("get property info: {0}", pi)
        
        pi.SetValue(s, 10, Nothing)
        Console.WriteLine("setting height with pi: {0}", s)
        
        Dim box As Object = s
        Console.WriteLine("boxing: {0}", box)
        
        ' 用InvokeMember设置属性,直接作用于原装箱实例
        sizeType.InvokeMember("Height", 
            BindingFlags.Public Or BindingFlags.Instance Or BindingFlags.SetProperty, 
            Nothing, 
            box, 
            New Object() {10})
        
        Console.WriteLine("setting value: {0}", box)
        Console.WriteLine(vbCrLf & "End test")
        Console.ReadLine()
    End Sub
End Module

方法2:通过中间变量传递并重新赋值

利用中间变量接收装箱实例,修改后将其重新赋值回原Object变量,确保保留修改后的实例:

Imports System.Drawing
Imports System.Reflection

Module Module1
    Sub Main()
        Console.WriteLine("Starting test")
        Dim s As Size
        Console.WriteLine("Created size: {0}", s)
        s.Width = 5
        Console.WriteLine("Set Width: {0}", s)
        
        Dim pi = s.GetType().GetProperty("Height")
        Console.WriteLine("get property info: {0}", pi)
        
        pi.SetValue(s, 10, Nothing)
        Console.WriteLine("setting height with pi: {0}", s)
        
        Dim box As Object = s
        Console.WriteLine("boxing: {0}", box)
        
        ' 中间变量传递,修改后重新赋值回原变量
        Dim tempBox As Object = box
        pi.SetValue(tempBox, 10, Nothing)
        box = tempBox
        
        Console.WriteLine("setting value: {0}", box)
        Console.WriteLine(vbCrLf & "End test")
        Console.ReadLine()
    End Sub
End Module

预期运行结果

修改后的VB代码运行后,输出将与C#版本一致:

Starting test
Created size: {Width=0, Height=0}
Set Width: {Width=5, Height=0}
get property info: Int32 Height
setting height with pi: {Width=5, Height=0}
boxing: {Width=5, Height=0}
setting value: {Width=5, Height=10}

End test

内容的提问来源于stack exchange,提问作者Johan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 19:40:55