.net 如何使用DynamicMethod.CreateDelegate返回带有实例对象的字段值

.net 如何使用DynamicMethod.CreateDelegate返回带有实例对象的字段值,.net,vb.net,dynamicmethod,.net,Vb.net,Dynamicmethod,如问题中所述,我对使用.net的动态特性缓存对象的字段getter/setter并在运行时调用它感兴趣 使用以下来源的信息: 我创建了一个类和函数,用于设置我需要的功能: 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 S

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

使用以下来源的信息:

我创建了一个类和函数,用于设置我需要的功能:

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
,以便能够以缓存的形式使用它,如:(缓存实例对象)


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

实际上,你不能用一种方法来完成这项工作。要永久保留该对象,需要在某个对象中创建一个字段,然后创建一个指向该对象上某个方法的委托

您可以使用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
的重载更有意义。

Hey@svick:)对于实例字段,您可以通过使用CreateDelegate的重载来实现这一点,只需使用一个“目标对象”。非常像这样:Hi@svick,fieldAccessor示例似乎不起作用,CreateDelegate需要第二个参数。不过,第二个例子似乎有效。由于我使用Getter从一条记录访问多个字段,然后遍历到下一条记录(即,000条记录),因此我希望通过缓存对象来获得性能增益,以便对每个对象上每个字段的Get调用进行性能优化,而不需要每次调用都传递object ref。理想情况下,我只需为每条记录设置一次obj ref,从理论上讲,这将提供比上述第一次尝试更好的性能。@stackmike_2014,
fieldAccessor
直接从您的代码复制而来,在我尝试它时,它工作正常。但我不明白为什么您希望在这里提高性能,因为每个字段都有一个单独的委托。是的,每个字段都有一个单独的委托。也许我应该再解释一下:我创建了一次这些代理的数组,每个字段1个。在DB大容量插入/更新之前从1000条记录中提取字段值时,我认为缓存每条记录的对象会更快,但现在我意识到这一点,我必须在该记录的每个字段中进行缓存,因此不会有性能提升,因为我无论如何都会在每个字段中传递obj ref get。。。谢谢你的评论斯维克,我认为我目前的代码可能是令人满意的。。。
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