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

obj を評価スタックにきれいにプッシュすることは明らかに不可能ですが、移植性などを損なう可能性のある醜いハックに対してオープンです。ModuleBuilder.DefineInitializedData を使用すると、System.Byte[] を .sdata に格納できます。何か案は?

編集: 生成されたメソッドは、新しいアセンブリの一部として発行されています。

4

2 に答える 2

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

ちなみに、目的に System.Linq.Expressions を使用できないことを確認してください。前後のANTLRプロジェクトのコードのセクションは次のとおりです。

前。これにはバグ (それに関するメーリング リストの投稿が見つかりません) があることに注意してください。"After" に切り替えることで副作用として修正されたため、見つける必要はありませんでした。

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();
}
于 2009-08-13T04:02:41.290 に答える
0

必要なオブジェクトをシリアル化し、リソース ストリーム (頻繁にアクセスする場合はキャッシュされている可能性があります) から逆シリアル化するための呼び出しを発行することをお勧めします。

于 2009-09-09T01:09:12.887 に答える