c# - 将对象字面量提供给 ILGenerator

标签 c# cil reflection.emit

Food obj = ...;
ILGenerator gen = (...).GetILGenerator();
gen.Emit( ?? obj ?? ); // replace this 
gen.Emit(OpCodes.Call, typeof(Person).GetMethod("Eat"));

显然不可能将 obj 干净地插入评估堆栈,但我对可能妥协的丑陋黑客持开放态度,例如可移植性。 ModuleBuilder.DefineInitializedData 允许将 System.Byte[] 存储在 .sdata 中。有什么想法吗?

编辑:生成的方法作为新程序集的一部分发出。

最佳答案

object o = ...;
Func<object> sneaky = () => o;
gen.Emit(OpCodes.Call, sneaky.Method);

附带说明,请确保您不能将 System.Linq.Expressions 用于您的目的。这是我在 ANTLR 项目中前后的一段代码:

之前。请注意,这里有一个错误(找不到关于它的邮件列表帖子),我不必找到它,因为切换到“之后”将其作为副作用纠正了。

private static Func<object, object> BuildAccessor(MethodInfo method)
{
    DynamicMethod dm = new DynamicMethod(method.DeclaringType.Name + method.Name + "MethodAccessor", typeof(object), new Type[] { typeof(object) }, method.DeclaringType);
    var gen = dm.GetILGenerator();

    if (!method.IsStatic)
    {
        gen.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);
        gen.Emit(System.Reflection.Emit.OpCodes.Castclass, method.DeclaringType);
    }

    if (method.IsVirtual && !method.IsFinal)
        gen.EmitCall(System.Reflection.Emit.OpCodes.Callvirt, method, null);
    else
        gen.EmitCall(System.Reflection.Emit.OpCodes.Call, method, null);

    if (method.ReturnType.IsValueType)
        gen.Emit(System.Reflection.Emit.OpCodes.Box, method.ReturnType);

    gen.Emit(System.Reflection.Emit.OpCodes.Ret);
    return (Func<object, object>)dm.CreateDelegate(typeof(Func<object, object>));
}

private static Func<object, object> BuildAccessor(FieldInfo field)
{
    DynamicMethod dm = new DynamicMethod(field.DeclaringType.Name + field.Name + "FieldAccessor", typeof(object), new Type[] { typeof(object) }, field.DeclaringType);

    var gen = dm.GetILGenerator();
    if (field.IsStatic)
    {
        gen.Emit(System.Reflection.Emit.OpCodes.Ldsfld, field);
    }
    else
    {
        gen.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);
        gen.Emit(System.Reflection.Emit.OpCodes.Castclass, field.DeclaringType);
        gen.Emit(System.Reflection.Emit.OpCodes.Ldfld, field);
    }

    if (field.FieldType.IsValueType)
        gen.Emit(System.Reflection.Emit.OpCodes.Box, field.FieldType);

    gen.Emit(System.Reflection.Emit.OpCodes.Ret);
    return (Func<object, object>)dm.CreateDelegate(typeof(Func<object, object>));
}

之后:

private static Func<object, object> BuildAccessor(MethodInfo method)
{
    ParameterExpression obj = Expression.Parameter(typeof(object), "obj");

    Expression<Func<object, object>> expr =
        Expression.Lambda<Func<object, object>>(
            Expression.Convert(
                Expression.Call(
                    Expression.Convert(obj, method.DeclaringType),
                    method),
                typeof(object)),
            obj);

    return expr.Compile();
}

private static Func<object, object> BuildAccessor(FieldInfo field)
{
    ParameterExpression obj = Expression.Parameter(typeof(object), "obj");

    Expression<Func<object, object>> expr =
        Expression.Lambda<Func<object, object>>(
            Expression.Convert(
                Expression.Field(
                    Expression.Convert(obj, field.DeclaringType),
                    field),
                typeof(object)),
            obj);

    return expr.Compile();
}

关于c# - 将对象字面量提供给 ILGenerator,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1269967/

相关文章:

c# - 将自定义对象添加到 C# 中的选中列表框

.net - IL中有评论这样的东西吗?

delegates - 是否有可能扩展 System.Delegate?

.net - 如何为通过 Reflection.Emit 创建的类型指定命名空间?

c# - 使用 Reflection.Emit 动态创建一个类。我被困

c# - 过滤以 `datagridview` 为界的 `datatable` 范围内的数据

c# - 将方法执行移动到单独的线程并接收返回值

c# - 我什么时候想用私有(private) ctor 模拟一个类(class)?

c# - 为什么C#不直接编译成机器码?

c# - 在虚拟方法上使用 OpCodes.Call 是否安全?