2011-01-17 17 views
7

का उपयोग कर मैं कैसे संकलन और गतिशील रूप से उत्पन्न सी # कोड को चलाने के लिए सी # कोड लिखा जा सकता है। क्या आसपास के उदाहरण हैं?संकलन कोड को गतिशील सी #

क्या मैं के बाद कर रहा हूँ गतिशील रूप से एक सी # वर्ग (या वर्ग) का निर्माण और उन्हें क्रम पर चलाने के लिए है। मैं जेनरेट क्लास को अन्य सी # कक्षाओं के साथ बातचीत करना चाहता हूं जो गतिशील नहीं हैं।

मुझे लगता है कि exe या dll फ़ाइलें उत्पन्न उदाहरण देखा है। मैं उसके बाद नहीं हूं, मैं बस इसे कुछ सी # कोड को स्मृति में संकलित करना चाहता हूं और फिर इसे चला सकता हूं। उदाहरण के लिए,

तो यहाँ एक वर्ग जो गतिशील नहीं है, यह मेरी सी # विधानसभा में परिभाषित किया जाएगा और केवल संकलन समय पर बदल जाएगा,

public class NotDynamicClass 
{ 
    private readonly List<string> values = new List<string>(); 

    public void AddValue(string value) 
    { 
     values.Add(value); 
    } 

    public void ProcessValues() 
    { 
     // do some other stuff with values 
    } 
} 

यहाँ मेरी कक्षा कि गतिशील है। मेरे सी # कोड इस वर्ग पैदा करते हैं और यह चलेगा,

public class DynamicClass 
{ 
    public static void Main() 
    { 
     NotDynamicClass class = new NotDynamicClass(); 

     class.AddValue("One"); 
     class.AddValue("two"); 
    } 
} 

तो नतीजा यह है कि अंत में मेरी गैर गतिशील कोड ProcessValues ​​कहेंगे और यह कुछ अन्य सामान करना होगा है। गतिशील कोड का बिंदु हमें या क्लाइंट को सॉफ़्टवेयर में कस्टम तर्क जोड़ने की अनुमति देना है।

धन्यवाद।

+2

यह विधानसभाओं "प्लगइन" संकलित करने के लिए और बस गतिशील सामान संकलन के बजाय क्रम में उन प्लग-इन लोड संभव है? –

+0

ठीक है, हाँ मैंने इसे किसी अन्य प्रोजेक्ट के लिए पहले किया है। यह संभव है, लेकिन वास्तव में हम इस परियोजना के लिए क्या नहीं कर रहे हैं। मैं इसे मानता हूं, धन्यवाद। – peter

उत्तर

15

दो संभावनाएं:

  1. Reflection.Emit
  2. System.CodeDom.Compiler

अद्यतन:

टिप्पणी अनुभाग में अनुरोध यहाँ Reflection.Emit के उपयोग को दर्शाता हुआ एक पूर्ण उदाहरण है के रूप में एक वर्ग को गतिशील रूप से बनाने और एक stati जोड़ने के लिए यह करने के लिए सी विधि:

using System; 
using System.Collections.Generic; 
using System.Reflection; 
using System.Reflection.Emit; 

public class NotDynamicClass 
{ 
    private readonly List<string> values = new List<string>(); 

    public void AddValue(string value) 
    { 
     values.Add(value); 
    } 

    public void ProcessValues() 
    { 
     foreach (var item in values) 
     { 
      Console.WriteLine(item); 
     } 
    } 
} 

class Program 
{ 
    public static void Main() 
    { 
     var assemblyName = new AssemblyName("DynamicAssemblyDemo"); 
     var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); 
     var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, false); 
     var typeBuilder = moduleBuilder.DefineType("DynamicClass", TypeAttributes.Public); 

     var methodBuilder = typeBuilder.DefineMethod(
      "Main", 
      MethodAttributes.Public | MethodAttributes.Static, 
      null, 
      new Type[0] 
     ); 

     var il = methodBuilder.GetILGenerator(); 
     var ctor = typeof(NotDynamicClass).GetConstructor(new Type[0]); 
     var addValueMi = typeof(NotDynamicClass).GetMethod("AddValue"); 
     il.Emit(OpCodes.Newobj, ctor); 
     il.Emit(OpCodes.Stloc_0); 
     il.DeclareLocal(typeof(NotDynamicClass)); 
     il.Emit(OpCodes.Ldloc_0); 
     il.Emit(OpCodes.Ldstr, "One"); 
     il.Emit(OpCodes.Callvirt, addValueMi); 
     il.Emit(OpCodes.Ldloc_0); 
     il.Emit(OpCodes.Ldstr, "Two"); 
     il.Emit(OpCodes.Callvirt, addValueMi); 
     il.Emit(OpCodes.Ldloc_0); 
     il.Emit(OpCodes.Callvirt, typeof(NotDynamicClass).GetMethod("ProcessValues")); 
     il.Emit(OpCodes.Ret); 
     var t = typeBuilder.CreateType(); 
     var mi = t.GetMethod("Main"); 
     mi.Invoke(null, new object[0]); 
    } 
} 

आप अपने नहीं NotDynamicClass तरीकों अंदर breakpoints डाल और देखें कि वे कैसे लागू हो सकता है।


अद्यतन 2:

यहाँ CodeDom संकलक के साथ एक उदाहरण है:

using System; 
using System.CodeDom.Compiler; 
using System.Collections.Generic; 
using Microsoft.CSharp; 

public class NotDynamicClass 
{ 
    private readonly List<string> values = new List<string>(); 

    public void AddValue(string value) 
    { 
     values.Add(value); 
    } 

    public void ProcessValues() 
    { 
     foreach (var item in values) 
     { 
      Console.WriteLine(item); 
     } 
    } 
} 

class Program 
{ 
    public static void Main() 
    { 
     var provider = CSharpCodeProvider.CreateProvider("c#"); 
     var options = new CompilerParameters(); 
     var assemblyContainingNotDynamicClass = Path.GetFileName(Assembly.GetExecutingAssembly().Location); 
     options.ReferencedAssemblies.Add(assemblyContainingNotDynamicClass); 
     var results = provider.CompileAssemblyFromSource(options, new[] 
     { 
@"public class DynamicClass 
{ 
    public static void Main() 
    { 
     NotDynamicClass @class = new NotDynamicClass(); 
     @class.AddValue(""One""); 
     @class.AddValue(""Two""); 
     @class.ProcessValues(); 
    } 
}" 
     }); 
     if (results.Errors.Count > 0) 
     { 
      foreach (var error in results.Errors) 
      { 
       Console.WriteLine(error); 
      } 
     } 
     else 
     { 
      var t = results.CompiledAssembly.GetType("DynamicClass"); 
      t.GetMethod("Main").Invoke(null, null); 
     } 
    } 
} 
+0

कोई भी अच्छा उदाहरण जो आप ऊपर करना चाहते हैं उससे संबंधित सुझाव देंगे? – peter

+0

@ पीटर, कृपया मेरा अपडेट देखें। मैंने एक उदाहरण जोड़ा है जो दिखाता है कि आप इसे विधियों को जोड़कर रनटाइम पर गतिशील रूप से कैसे बना सकते हैं और अंत में उन तरीकों का आह्वान करते हैं। –

+0

इसके लिए धन्यवाद। यही वह है जो मुझे डर था और मैंने कहीं और क्या देखा है। आप GetILGenerator का उपयोग करके एक विधि बना रहे हैं और il.Emit आदि को कॉल कर रहे हैं। क्या कोड लिखने का कोई तरीका नहीं है, उस स्ट्रिंग को निर्दिष्ट करें जिसमें कोड है और ऊपर 'मेरे दूसरे कोड उदाहरण की तरह' चलाएं 'कहें।कारण यह है कि हम इन स्क्रिप्ट को 'टेक्स्ट' के रूप में लिखना चाहते हैं और उन्हें डीबी में स्टोर करना चाहते हैं। – peter

2

मोनो एक C# compiler as a service कि विंडोज पर NET अनुप्रयोगों में प्रयोग करने योग्य है (लिनक्स के साथ, निश्चित रूप से) है।

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