.NET 3.5 を使用して、VB.net アプリのプロパティの Set メソッドを呼び出す動的メソッドを作成するための次のコードがあります (ラムダ式スタイルに切り替えることはできません)。ここに投稿された例を使用して、Int64
プロパティで機能しなかったため、関数に追加しました。主に、通常int
の unbox 操作で呼び出された場合、無効なキャストエラーが発生するためです。そのため、それを処理するコードを追加しましたが、新しい問題が発生しました。64 ビットで実行している場合はすべて正常に動作しますが、32 ビット プロセスに変更するとすぐに、Int64
プロパティのデリゲートを呼び出すと、AccessViolationException
保護されたメモリの読み取りまたは書き込みが試行されます。String のような他のタイプは、正常に動作するようです。以下のコードを参照してください。何が間違っていますか?
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