如何使用它们DynamicMethod.CreateDelegate用一个实例对象返回一个字段值字段、如何使用、实例、对象

2023-09-06 10:56:19 作者:Anesthesia麻醉

由于在规定的问题,我有兴趣使用.NET的动态特性,缓存中的对象的字段的getter / setter并在运行时调用它。

As specified in the question, I am interested in using the Dynamic features of .net to cache an object's field getter/setter and calling it at runtime.

使用信息来源: Is有没有一种方法创建一个委托来获取和设置值的字段信息?

我已经把一个类和功能设置,我需要的功能:

I have put together a class and function that set up the functionality that I need:

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

我把这个好code有:

I call this good code with:

Dim getValue = CreateGetter(Of c1, Integer)("someField")
Dim someValue As Integer
someValue = getValue(o1)

不过,我难倒的部分是如何修改函数 CreateGetter ,以便能够使用它在缓存的形式,如:(缓存实例对象)

However, the part I am stumped at is how to modify function CreateGetter to be able to use it in a cached form like: (caching the instance object)

Dim getValue = CreateGetter(Of c1, Integer)(o1,"someField")
Dim someValue As Integer
someValue = getValue()

我意识到这可能需要的IL code一些改装的 CreateGetter 但是这是我停留在棘手的部分。

I realize this may require some modding of the IL code in CreateGetter but that is the tricky part that I am stuck at.

推荐答案

其实,你可以使用一个单一的方法无法做到这一点。要永久保存对象,你在某个对象需要一个字段,然后创建一个委托指向该对象的一些方法。

Actually, you can't do this using a single method. To hold the object permanently, you need a field in some object and then create a delegate that points to some method on that object.

您可以做的一切使用Reflection.Emit的,但是这将是乏味的。相反,你可以利用的事实,即编译器已经可以做到这一点创建闭包:不是直接返回 DynamicMethod的委托,返回一个lambda调用该委托:

You could do all that using Reflection.Emit, but that would be tedious. Instead, you can take advantage of the fact that the compiler can already do this to create closures: instead of returning the DynamicMethod delegate directly, you return a lambda that invokes that delegate:

Dim fieldAccessor = DirectCast(objGetterMethod.CreateDelegate(GetType(Func(Of S, T))), Func(Of S, T))

Return Function() fieldAccessor(obj)

另一种选择是使用防爆pression树的这一切。这样做,你不必应付IL,它可以是很难得到正确的优势。是这样的:

Another option would be to use Expression Trees for all of this. This has the advantage that you don't have to deal with IL, which can be hard to get right. Something like:

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

 
精彩推荐