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

पर ऑब्जेक्ट को शाब्दिक रूप से फ़ीड करना स्पष्ट रूप से मूल्यांकन स्टैक पर ओबीजे को साफ़ करना संभव नहीं है, लेकिन मैं बदसूरत हैक के लिए खुला हूं जो समझौता कर सकता है उदा। पोर्टेबिलिटी। ModuleBuilder.DefineInitializedData किसी को .sdata में System.Byte [] को स्टोर करने की अनुमति देता है। कोई विचार?आईएलजीनरेटर

संपादित करें: जेनरेट की गई विधि को एक नई असेंबली के हिस्से के रूप में उत्सर्जित किया जा रहा है।

उत्तर

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

एक तरफ ध्यान दें, सुनिश्चित करें कि आप अपने उद्देश्य के लिए System.Linq.Expressions का उपयोग नहीं कर सकते हैं। पहले और बाद में एएनटीएलआर परियोजना में मेरे कोड का एक अनुभाग यहां दिया गया है:

इससे पहले। ध्यान दें कि इसमें एक बग है (इसके बारे में मेलिंग सूची पोस्ट नहीं मिल रहा है) कि मुझे यह नहीं मिला क्योंकि "बाद में" स्विच को साइड इफेक्ट के रूप में सही किया गया था।

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

इसका परिणाम एक विधिAccessException में होता है क्योंकि स्थानीय रूप से परिभाषित लैम्ब्डा नई विधि में उपलब्ध नहीं है। – shivak

+0

यह दिलचस्प है, क्योंकि यह वही है जो मैं अपने प्रयोगात्मक स्ट्रिंग टेम्पलेट कंपाइलर में करता हूं (और यह वहां काम करता है)। –

+0

क्षमा करें, मेरा मतलब है कि उत्सर्जित नई असेंबली से पहुंच योग्य नहीं है। वहां उपलब्ध एक संदर्भ प्रकार बनाना अनुचित लगता है और इसलिए मैंने शुरुआत में महसूस किया कि एक क्लज आवश्यक होगा। – shivak

0

मैं वस्तु आप की जरूरत serializing, और एक संसाधन स्ट्रीम से deserialize के लिए एक कॉल उत्सर्जक सुझाव है (संभवतः, कैश्ड आप बार-बार इसे का उपयोग करने के लिए जा रहे हैं)।