1

如问题中所述,我有兴趣使用 .net 的动态功能来缓存对象的字段 getter/setter 并在运行时调用它。

使用来自的信息: 有没有办法创建一个委托来获取和设置 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()

我意识到这可能需要对 IL 代码进行一些修改,CreateGetter但这是我遇到的棘手部分。

4

1 回答 1

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更有意义。

于 2014-08-08T11:36:36.320 回答