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
相关产品推荐
相关产品推荐

