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

Net olarak değerlendirme yığınının üstüne itmek mümkün değildir, ancak, örn. taşınabilirlik. ModuleBuilder.DefineInitializedData, bir .sdata dosyasında System.Byte [] depolamasını sağlar. Herhangi bir fikir?Bir nesneyi ILGenerator ile beslemek

Düzenleme: oluşturulan yöntem yeni bir grubun parçası olarak yayılıyor.

cevap

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

Bir yan notta, amacınız için System.Linq.Expressions kullanamadığınızdan emin olun. Aşağıda, ANTLR projesindeki kodumun bir bölümü ve öncesi:

Önceden. Bunun içinde bir hata olduğunu (bu konuyla ilgili posta listesi gönderisini bulamıyorum), “Sonra” seçeneğinin bir yan etki olarak düzeltilmesi gerektiğinden bulamayacağımı unutmayın.

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>)); 
} 

sonra:

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

Bu, MethodAccessException ile sonuçlanır, çünkü yerel olarak tanımlanan lambda yeni yönteme erişilemez. – shivak

+0

Bu ilginç, çünkü benim deneysel StringTemplate derleyicimde tam olarak yaptığım şey (ve orada çalışıyor). –

+0

Üzgünüm, yayılan yeni meclisten erişilemez demek istedim. Mevcut bir referans türü yapmak mantıksız görünüyor ve bu yüzden başlangıçta bir klozun gerekli olacağını hissettim. – shivak

0

I (sık sık erişmek için gidiyoruz eğer muhtemelen önbelleğe) ihtiyacınız nesne seri ve kaynak akışından bu serisini için bir çağrı yayan öneririz.