2009-08-13 3 views
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. Есть идеи?Кормление объекта литералом ILGenerator

Редактировать: генерируемый метод испускается как часть новой сборки.

ответ

1
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(); 
} 
+0

Это приводит к исключению MethodAccessException, поскольку локально определенная лямбда недоступна в новом методе. – shivak

+0

Это интересно, потому что это именно то, что я делаю в своем экспериментальном компиляторе StringTemplate (и там он работает). –

+0

Извините, я имел в виду недоступную из новой сборки, которая испускается. Создание ссылочного типа, доступного там, кажется необоснованным, и именно поэтому я изначально почувствовал, что нужно клод. – shivak

0

Я хотел бы предложить сериализации вам объект, и испуская вызов десериализации его из потока ресурсов (возможно, в кэше, если вы собираетесь получить доступ к нему часто).

Смежные вопросы