正如问题所述,我有兴趣使用.net的动态功能来缓存对象的字段getter / setter并在运行时调用它。
使用以下信息: Is there a way to create a delegate to get and set values for a FieldInfo?
我已经组建了一个类和函数来设置我需要的功能:
Public Class c1
Public someField As Integer 'we will Get the value of this dynamically
End Class
Public Function CreateGetter(Of S, T)(ByVal strFieldName As String) As Func(Of S, T)
'creates a function to return the value
Dim objFieldInfo As FieldInfo
Dim strMethodName As String
Dim objGetterMethod As DynamicMethod
Dim objGen As ILGenerator
objFieldInfo = GetType(S).GetField(strFieldName)
strMethodName = Convert.ToString(objFieldInfo.ReflectedType.FullName) & ".get_" & Convert.ToString(objFieldInfo.Name)
objGetterMethod = New DynamicMethod(strMethodName, GetType(T), New Type(0) {GetType(S)}, True)
objGen = objGetterMethod.GetILGenerator()
If objFieldInfo.IsStatic = False Then
objGen.Emit(OpCodes.Ldarg_0)
objGen.Emit(OpCodes.Ldfld, objFieldInfo)
Else
objGen.Emit(OpCodes.Ldsfld, objFieldInfo)
End If
objGen.Emit(OpCodes.Ret)
Return DirectCast(objGetterMethod.CreateDelegate(GetType(Func(Of S, T))), Func(Of S, T))
End Function
我用以下代码称之为好的代码:
Dim getValue = CreateGetter(Of c1, Integer)("someField")
Dim someValue As Integer
someValue = getValue(o1)
然而,我所困扰的部分是如何修改函数CreateGetter
以便能够以缓存的形式使用它,如:(缓存实例对象)
Dim getValue = CreateGetter(Of c1, Integer)(o1,"someField")
Dim someValue As Integer
someValue = getValue()
我意识到这可能需要对CreateGetter
中的IL代码进行一些修改,但这是我遇到的棘手问题。
答案 0 :(得分:1)
实际上,您无法使用单一方法执行此操作。要永久保存对象,您需要在某个对象中使用一个字段,然后创建一个指向该对象上某个方法的委托。
你可以使用Reflection.Emit做所有这些,但那将是乏味的。相反,您可以利用编译器已经可以执行此操作来创建闭包的事实:您不是直接返回DynamicMethod
委托,而是返回调用该委托的lambda:
Dim fieldAccessor = DirectCast(objGetterMethod.CreateDelegate(GetType(Func(Of S, T))), Func(Of S, T))
Return Function() fieldAccessor(obj)
另一种选择是将表达式树用于所有这些。这样做的好处是您不必处理IL,这可能很难做到。类似的东西:
Function CreateGetter(Of S, T)(obj as S, fieldName As String) As Func(Of T)
Dim expr = Expression.Lambda(Of Func(Of T))(
Expression.Field(Expression.Constant(obj), fieldName))
Return expr.Compile()
End Function
此版本仅适用于实例字段,我认为对于静态字段,不使用obj
的重载更有意义。