C# 将对象文本馈送到ILGenerator

C# 将对象文本馈送到ILGenerator,c#,cil,reflection.emit,C#,Cil,Reflection.emit,显然不可能将obj干净地推到评估堆栈上,但我对可能会影响可移植性的丑陋的黑客行为持开放态度。ModuleBuilder.DefineInitializeData允许在.sdata中存储System.Byte[]。有什么想法吗 编辑:生成的方法将作为新程序集的一部分发出。object o=。。。; Food obj = ...; ILGenerator gen = (...).GetILGenerator(); gen.Emit( ?? obj ?? ); // replace this gen

显然不可能将obj干净地推到评估堆栈上,但我对可能会影响可移植性的丑陋的黑客行为持开放态度。ModuleBuilder.DefineInitializeData允许在.sdata中存储System.Byte[]。有什么想法吗

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

object o=。。。;
Food obj = ...;
ILGenerator gen = (...).GetILGenerator();
gen.Emit( ?? obj ?? ); // replace this 
gen.Emit(OpCodes.Call, typeof(Person).GetMethod("Eat"));
Func flecky=()=>o; gen.Emit(操作码.调用,鬼祟.方法);
另一方面,请确保不能出于您的目的使用System.Linq.Expressions。以下是我在ANTLR项目前后的代码部分:

以前。请注意,这其中有一个bug(找不到关于它的邮件列表帖子),我没有找到它,因为切换到“After”会纠正它的副作用

object o = ...;
Func<object> sneaky = () => o;
gen.Emit(OpCodes.Call, sneaky.Method);
private static Func BuildAccessor(MethodInfo方法)
{
DynamicMethod dm=newdynamicmethod(method.DeclaringType.Name+method.Name+“MethodAccessor”、typeof(object)、newtype[]{typeof(object)}、method.DeclaringType);
var gen=dm.GetILGenerator();
如果(!method.IsStatic)
{
gen.Emit(System.Reflection.Emit.opcode.Ldarg_0);
gen.Emit(System.Reflection.Emit.OpCodes.Castclass、method.DeclaringType);
}
if(method.IsVirtual&&!method.IsFinal)
gen.EmitCall(System.Reflection.Emit.OpCodes.Callvirt,方法,null);
其他的
gen.EmitCall(System.Reflection.Emit.OpCodes.Call,方法,null);
if(method.ReturnType.IsValueType)
gen.Emit(System.Reflection.Emit.opcode.Box,method.ReturnType);
gen.Emit(System.Reflection.Emit.opcode.Ret);
return(Func)dm.CreateDelegate(typeof(Func));
}
专用静态Func BuildAccessor(FieldInfo字段)
{
DynamicMethod dm=newdynamicmethod(field.DeclaringType.Name+field.Name+“FieldAccessor”、typeof(object)、newtype[]{typeof(object)}、field.DeclaringType);
var gen=dm.GetILGenerator();
if(字段IsStatic)
{
gen.Emit(System.Reflection.Emit.opcode.Ldsfld,字段);
}
其他的
{
gen.Emit(System.Reflection.Emit.opcode.Ldarg_0);
gen.Emit(System.Reflection.Emit.OpCodes.Castclass、field.DeclaringType);
gen.Emit(System.Reflection.Emit.opcode.Ldfld,字段);
}
if(field.FieldType.IsValueType)
gen.Emit(System.Reflection.Emit.opcode.Box,field.FieldType);
gen.Emit(System.Reflection.Emit.opcode.Ret);
return(Func)dm.CreateDelegate(typeof(Func));
}
之后:

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 BuildAccessor(MethodInfo方法)
{
ParameterExpression obj=表达式。参数(typeof(object),“obj”);
表达式表达式=
Lambda(
表达式。转换(
表情,打电话(
表达式.Convert(obj,方法.DeclaringType),
方法),
类型(对象)),
obj);
返回expr.Compile();
}
专用静态Func BuildAccessor(FieldInfo字段)
{
ParameterExpression obj=表达式。参数(typeof(object),“obj”);
表达式表达式=
Lambda(
表达式。转换(
表达式字段(
表达式.Convert(对象,字段.DeclaringType),
字段),
类型(对象)),
obj);
返回expr.Compile();
}

我建议序列化您需要的对象,并发出一个调用,从资源流(可能是缓存的,如果您要经常访问它)对其进行反序列化。

这会导致MethodAccessException,因为在新方法中无法访问本地定义的lambda。这很有趣,因为这正是我在我的实验性StringTemplate编译器中所做的(它在那里工作)。对不起,我的意思是从发出的新程序集无法访问。在那里使用引用类型似乎不合理,这就是为什么我最初觉得有必要使用一个乱七八糟的引用类型。显然,你不能新建一个对象并像那样发出它。我认为这是一种
动态方法
。对于您所说的,发出
newobj
指令,或者创建一个具有静态方法/属性的类,您可以调用该类来返回由发出的程序集的代码在运行时创建的对象。发出新程序集的程序终止,新程序集单独使用。因此,无论采用哪种方法,传递对象值的问题仍然存在。我希望有比在模块中将对象序列化为初始化数据更好的方法。
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();
}