我有以下代码用于创建动态方法来调用我的 VB.net 应用程序中的属性的 Set 方法,使用 .NET 3.5(无法切换到 Lambda 表达式样式)。使用此处发布的示例,我添加了该函数,因为它不适用于Int64
属性,主要是如果使用常规调用它int
,取消装箱操作会导致 Invalid Cast 错误。所以我添加了代码来处理这个问题,但现在我遇到了一个新问题。在 64 位下运行时一切正常,但是一旦我更改为 32 位进程,调用委托的Int64
属性会导致AccessViolationException
, 尝试读取或写入受保护的内存。其他类型,如字符串,似乎工作正常。请参阅下面的代码,我做错了什么?
Public Shared Sub SetFieldData(Instance As Object, PropInfo As PropertyInfo, value As Object)
Dim Compiled As Action(Of Object, Object) = Nothing
If Not _PropSetterCache.TryGetValue(PropInfo, Compiled) Then
SyncLock _PropSetterCache
If Not _PropSetterCache.TryGetValue(PropInfo, Compiled) Then
'http://jachman.wordpress.com/2006/08/22/2000-faster-using-dynamic-method-calls/
Dim setMethod = PropInfo.GetSetMethod()
Dim arguments As Type() = New Type(1) {}
arguments(0) = GetType(Object)
arguments(1) = arguments(0)
Dim setter As New DynamicMethod([String].Concat("_Set", PropInfo.Name, "_"), Nothing, arguments, PropInfo.DeclaringType)
Dim generator As ILGenerator = setter.GetILGenerator()
generator.Emit(OpCodes.Ldarg_0)
generator.Emit(OpCodes.Castclass, PropInfo.DeclaringType)
If PropInfo.PropertyType.IsClass Then
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Castclass, PropInfo.PropertyType)
ElseIf PropInfo.PropertyType Is GetType(Boolean) Then
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Unbox_Any, PropInfo.PropertyType)
ElseIf PropInfo.PropertyType.IsValueType Then
'my stuff, blog example doesn't cover the sent value being different type than the property
Dim LByte = generator.DefineLabel
Dim LInt = generator.DefineLabel
Dim LInt16 = generator.DefineLabel
Dim LInt32 = generator.DefineLabel
Dim LInt64 = generator.DefineLabel
Dim LSByte = generator.DefineLabel
Dim LUInt16 = generator.DefineLabel
Dim LUInt32 = generator.DefineLabel
Dim LUInt64 = generator.DefineLabel
Dim LDouble = generator.DefineLabel
Dim LSingle = generator.DefineLabel
Dim LElse = generator.DefineLabel
Dim LEnd = generator.DefineLabel
'byte
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Isinst, GetType(Byte))
generator.Emit(OpCodes.Brtrue, LByte)
'int
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Isinst, GetType(Integer))
generator.Emit(OpCodes.Brtrue, LInt)
'int16
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Isinst, GetType(Int16))
generator.Emit(OpCodes.Brtrue, LInt16)
'int32
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Isinst, GetType(Int32))
generator.Emit(OpCodes.Brtrue, LInt32)
'int64
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Isinst, GetType(Int64))
generator.Emit(OpCodes.Brtrue, LInt64)
'double
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Isinst, GetType(Double))
generator.Emit(OpCodes.Brtrue, LDouble)
'short
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Isinst, GetType(Single))
generator.Emit(OpCodes.Brtrue, LSingle)
'sbyte
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Isinst, GetType(SByte))
generator.Emit(OpCodes.Brtrue, LSByte)
'uint16
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Isinst, GetType(UInt16))
generator.Emit(OpCodes.Brtrue, LUInt16)
'uint32
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Isinst, GetType(UInt32))
generator.Emit(OpCodes.Brtrue, LUInt32)
'uint64
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Isinst, GetType(UInt64))
generator.Emit(OpCodes.Brtrue, LUInt64)
'else
generator.Emit(OpCodes.Br, LElse)
'
generator.MarkLabel(LByte)
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Unbox_Any, GetType(Byte))
generator.Emit(OpCodes.Br, LEnd)
'
generator.MarkLabel(LInt)
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Unbox_Any, GetType(Integer))
generator.Emit(OpCodes.Br, LEnd)
'
generator.MarkLabel(LInt16)
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Unbox_Any, GetType(Int16))
generator.Emit(OpCodes.Br, LEnd)
'
generator.MarkLabel(LInt32)
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Unbox_Any, GetType(Int32))
generator.Emit(OpCodes.Br, LEnd)
'
generator.MarkLabel(LInt64)
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Unbox_Any, GetType(Int64))
generator.Emit(OpCodes.Br, LEnd)
'
generator.MarkLabel(LDouble)
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Unbox_Any, GetType(Double))
generator.Emit(OpCodes.Br, LEnd)
'
generator.MarkLabel(LSingle)
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Unbox_Any, GetType(Single))
generator.Emit(OpCodes.Br, LEnd)
'
generator.MarkLabel(LSByte)
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Unbox_Any, GetType(SByte))
generator.Emit(OpCodes.Br, LEnd)
'
generator.MarkLabel(LUInt16)
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Unbox_Any, GetType(UInt16))
generator.Emit(OpCodes.Br, LEnd)
'
generator.MarkLabel(LUInt32)
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Unbox_Any, GetType(UInt32))
generator.Emit(OpCodes.Br, LEnd)
'
generator.MarkLabel(LUInt64)
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Unbox_Any, GetType(UInt64))
generator.Emit(OpCodes.Br, LEnd)
'
generator.MarkLabel(LElse)
generator.Emit(OpCodes.Ldarg_1)
generator.Emit(OpCodes.Unbox_Any, PropInfo.PropertyType)
generator.Emit(OpCodes.Br, LEnd)
generator.MarkLabel(LEnd)
End If
generator.Emit(OpCodes.Callvirt, setMethod)
generator.Emit(OpCodes.Ret)
Compiled = setter.CreateDelegate(GetType(Action(Of Object, Object)))
_PropSetterCache.Add(PropInfo, Compiled)
End If
End SyncLock
End If
Compiled(Instance, value)
End Sub