我试图将结构传递给子/ void以用数据填充它。在C#中,通过执行
可以正常工作[TestFixture]
public class Boxing
{
[Test]
public void BoxingValue()
{
var res = (object)new Test();
SomeVoid(res);
Assert.AreEqual(2, ((Test)res).Id);
}
public static void SomeVoid(object b)
{
var f = b.GetType().GetField("Id");
f.SetValue(b, 2);
}
public struct Test
{
public int Id;
}
}
此代码在vb thoug
中通过C#中的测试<Test> Public Sub StructTest()
Dim s As Object
s = CObj(New Test)
A(s)
Assert.AreEqual(2, CType(s, Test).Id)
End Sub
Public Sub A(val As Object)
Dim f = val.GetType().GetField("Id")
f.SetValue(val, 2)
End Sub
Public Structure Test
Public Id As Integer
End Structure
有没有人对此有解释..
STRANGE吗
答案 0 :(得分:7)
我认为这是一个已知的限制,在传递结构时在VB中使用SetValue
(即使变量本身被声明为Object
)。如果您在调用val
之前和之后查看A
内的SetValue
内容,您会发现它不会更改结构的值。我看到的解释是VB在内部再次将基础值打包(通过调用GetObjectValue
),创建副本,并更改副本的值
我看到的一个解决方法是将值转换为ValueType
并在其上调用SetValue
(您还需要将参数更改为显式ByRef:
Public Sub A(ByRef val As Object)
Dim f = val.GetType().GetField("Id")
If val.GetType.IsValueType Then
Dim vt As ValueType = val
f.SetValue(vt, 2)
val = vt
Else
f.SetValue(val, 2)
End If
End Sub
当然,这种复杂性只是强化了应该不惜一切代价避免可变结构的原则。
答案 1 :(得分:2)
请参阅Reflection on structure differs from class - but only in code进行解释,但总结如下:
f.SetValue(val*, 2)
* {此时val正在按值传递,即它是正在更新的副本}
至于解决方法......
'Struct workaround of course you only want this for structs!:
Public Sub A(ByRef val As Object)
Dim x As ValueType
x = CType(val, ValueType)
Dim f = x.GetType().GetField("Id")
f.SetValue(x, 2)
val = x
End Sub
显然你需要保护自己只为结构运行...