2010-08-19 9 views
5

मैं सी # का उपयोग स्क्रिप्टिंग भाषा के रूप में करते हुए भिन्न जटिलता के टोकनयुक्त उपयोगकर्ता परिभाषित अभिव्यक्तियों का मूल्यांकन करने के लिए एक परियोजना पर काम कर रहा हूं।Reflection.Emit का उपयोग करके एक शाब्दिक अभिव्यक्ति इंजेक्ट कैसे कर सकते हैं?

मेरे पास कोडडॉम का उपयोग करके एक वर्किंग मॉडल है और मूल्यांकनकर्ता वर्ग उत्पन्न करने के लिए प्रतिबिंब है, असेंबली बनाएं और लोड करें (जेनरेट इनमेमरी = सत्य), कक्षा को तुरंत चालू करें, और मूल्यांकन विधि निष्पादित करें। हालांकि, मैं एपडॉमेन में असेंबली लोड करना चाहता हूं ताकि निष्पादन पूरा होने पर मैं इसे अनलोड कर सकूं। इस मुद्दे पर शोध करते समय, मुझे AppDomain.DefineDynamicAssembly विधि पर निर्देशित किया गया था। यह वही है जो मुझे चाहिए, क्योंकि मैं एक संग्रहणीय असेंबली बना सकता हूं।

यहाँ उपयोगकर्ता परिभाषित भाव के उदाहरण के एक जोड़े हैं, और कक्षाओं मेरी CodeDOM परियोजना द्वारा उत्पन्न:

सरल उपयोगकर्ता परिभाषित अभिव्यक्ति:

return Abs(@[email protected]/@[email protected] * 5.5); 

जनरेट किया वर्ग:

namespace Lab.ResultProcessing 
{ 

    public sealed class ExpressionEvaluator 
    { 
     public double Evaluate() 
     { 
      return System.Math.Abs(449.86881550861/74.934407754305 * 5.5); 
     } 
    } 
} 

अधिक जटिल उपयोगकर्ता परिभाषित अभिव्यक्ति:

double GFR; 
double MA_GFR; 
double MB_GFR; 
double FA_GFR; 
double FB_GFR; 

GFR = (170 * 
     Pow(@[email protected], -0.999) * 
     Pow(@[email protected], -0.176) * 
     Pow(@[email protected], -0.170) * 
     Pow(@[email protected], 0.318)); 

MA_GFR = GFR; 
MB_GFR = GFR * 1.180; 
FA_GFR = GFR * 0.762; 
FB_GFR = GFR * 1.180 * 0.762; 

if (("@[email protected]" != "B") && ("@[email protected]" == "M")) 
{ 
    return MA_GFR; 
} 
else if (("@[email protected]" == "B") && ("@[email protected]" == "M")) 
{ 
    return MB_GFR; 
} 
else if (("@[email protected]" != "B") && ("@[email protected]" == "F")) 
{ 
    return FA_GFR; 
} 
else if (("@[email protected]" == "B") && ("@[email protected]" == "F")) 
{ 
    return FB_GFR; 
} 
else 
{ 
    return GFR; 
} 

जनरेट किया वर्ग:

namespace Lab.ResultProcessing 
{ 

    public sealed class ExpressionEvaluator 
    { 
     public double Evaluate() 
     { 
      double GFR; 
double MA_GFR; 
double MB_GFR; 
double FA_GFR; 
double FB_GFR; 

GFR = (170 * 
     System.Math.Pow(0.797258181752292, -0.999) *  
     System.Math.Pow(63.6814545438073, -0.176) * 
     System.Math.Pow(5.47258181752292, -0.170) *  
     System.Math.Pow(3.79725818175229, 0.318));  

MA_GFR = GFR;         
MB_GFR = GFR * 1.180;       
FA_GFR = GFR * 0.762;       
FB_GFR = GFR * 1.180 * 0.762;     

if (("B" != "B") && ("M" == "M")) 
{ 
    return MA_GFR;        
} 
else if (("B" == "B") && ("M" == "M")) 
{ 
    return MB_GFR;        
} 
else if (("B" != "B") && ("M" == "F")) 
{ 
    return FA_GFR;        
} 
else if (("B" == "B") && ("M" == "F")) 
{ 
    return FB_GFR;        
} 
else 
{ 
    return GFR; 
} 
; 
     } 
    } 
} 

मैं अब Reflection.Emit का उपयोग कर ऊपर वर्णित कार्यक्षमता नकल करने का प्रयास कर रहा हूँ। मेरी समस्या यह है कि मुझे उत्सर्जित कक्षा में detokenized सूत्र को इंजेक्ट करने का कोई तरीका नहीं मिला है।

यहाँ कोड मैं का उपयोग कर रहा है:

public static object DynamicEvaluate2(string expression) 
{ 
    AssemblyName assemblyName = new AssemblyName("Lab.ResultProcessing"); 
    AppDomain appDomain = AppDomain.CurrentDomain; 
    AssemblyBuilder assemblyBuilder = appDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndCollect); 
    ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); 
    TypeBuilder typeBuilder = moduleBuilder.DefineType("ExpressionEvaluator", TypeAttributes.Sealed); 
    MethodBuilder methodBuilder = typeBuilder.DefineMethod("Evaluate", MethodAttributes.Public | MethodAttributes.Final, typeof(double), null); 
    ILGenerator methodGenerator = methodBuilder.GetILGenerator(); 

    methodGenerator.Emit(OpCodes.Ldobj, expression); 
    methodGenerator.Emit(OpCodes.Ret); 

    Type evaluatorType = typeBuilder.CreateType(); 
    MethodInfo methodInfo = evaluatorType.GetMethod("Evaluate"); 

    object evaluator = Activator.CreateInstance(evaluatorType); 
    object result = methodInfo.Invoke(evaluator, null); 

    return result; 
} 

जब methodInfo.Invoke विधि कहा जाता है मैं निम्नलिखित त्रुटि मिलती है: सिस्टम:

टेस्ट विधि ResultCalculatorTest.ResultCalculatorClassFactoryTest.DynamicEvaluate2Test अपवाद फेंक दिया। प्रतिबिंब। लक्ष्यInvocationException: एक आमंत्रण के लक्ष्य से अपवाद फेंक दिया गया है। ---> System.BadImageFormatException: खराब वर्ग टोकन।

कैसे में detokenized उपयोगकर्ता परिभाषित Reflection.Emit का उपयोग कर अभिव्यक्ति इंजेक्षन कर सकते हैं:

तो मैं सवालों की एक जोड़ी है?
क्या उत्सर्जित वर्ग के लिए सी # कोड देखने का कोई तरीका है, या यह केवल आईएल में है?
मैं उत्सर्जित कक्षा को कैसे डीबग करूं?

किसी भी मदद की सराहना की जाएगी।

+0

'अभिव्यक्ति' स्ट्रिंग क्या है? –

+0

अभिव्यक्ति स्ट्रिंग ऊपर सूचीबद्ध उदाहरणों के समान होगी, जैसे "रिटर्न एब्स (@ एचडीएल @/@ एलडीएल @ * 5.5);" लेकिन यह और अधिक जटिल हो सकता है। –

+1

आप * अपने स्वयं के ऐपडोमेन के साथ कोडडॉम का उपयोग कर सकते हैं - कोडडॉम एक वास्तविक डीडीएल थूक जाएगा जो आप निश्चित रूप से अपने ऐपडोमेन में लोड करने के लिए आगे बढ़ सकते हैं। (इसके अलावा, आपके उदाहरण में, आप एक अलग ऐपडोमेन का उपयोग नहीं कर रहे हैं) –

उत्तर

5
methodGenerator.Emit(OpCodes.Ldobj, expression); 

यह वही है कि आप इसे करना चाहते हैं नहीं करता है: ldobj अनुदेश एक Type, नहीं एक string की उम्मीद है। एमएसडीएन के अनुसार, ldobj निर्देश का उद्देश्य copy the value type object pointed to by an address है।

कोडडॉम के विपरीत, प्रतिबिंब। प्रवेश आपके लिए अपनी अभिव्यक्ति का विश्लेषण नहीं करेगा। आपके कोड को expression स्ट्रिंग को पार्स करने की आवश्यकता होगी और उस अभिव्यक्ति की गणना करने के लिए आईएल ऑपकोड के दाएं अनुक्रम को छोड़ दें। असल में, आपको अपना खुद का कंपाइलर लिखना होगा।

प्रतिबिंब का एक विकल्प।एमिट System.Linq.Expressions में प्रकार है। ये प्रतिबिंब से उच्च स्तर हैं। कोडडॉम से प्रवेश और निचला स्तर। आपको अभी भी अपनी स्ट्रिंग को पार्स करने की आवश्यकता होगी, लेकिन आप कच्चे ऑपोड को उत्सर्जित करने के बजाय स्मृति में एक सार वाक्यविन्यास पेड़ तैयार करेंगे।

+0

मुझे इससे डर था। मैं उपयोगकर्ता द्वारा परिभाषित अभिव्यक्तियों को पार्स करने में नहीं आना चाहता हूं। मैं अपनी मूल परियोजना में वापस आ रहा हूं। –

संबंधित मुद्दे

 संबंधित मुद्दे