zoukankan      html  css  js  c++  java
  • .NET运行时编译学习——CodeDomProvider、CodeCompileUnit和CODEDOM(学习资料积累)

    强烈推荐

    CODEDOM学习系列:http://www.cnblogs.com/lichdr/category/12610.html

    .net项目的二次开发解决方案 :http://www.cnblogs.com/nuaalfm/archive/2008/11/14/1333381.html

    反射插件应用系列:http://www.cnblogs.com/nuaalfm/archive/2008/09/08/1286640.html

    转载几篇英文文章:

    http://www.codeproject.com/KB/cs/CodeDomCompile.aspx

    Download demo project (VS2008) - 1,840 Kb

    Introduction

    This is a bit of a strange article, and may not be that useful, but I think its a very interesting subject, that some will probably not even be aware of. This article will cover some of the less known namespaces within .NET. Such as System.CodeDom and System.CodeDom.Compiler. What I will be demonstrating in this article, is just how neat these namespaces are and what can be done with them. Specifically I will be demonstrating that we are able to build entirely new source code files at runtime using the System.CodeDom namespace and the use the System.CodeDom.Compiler namespace classes to even compile this newly created source code into a runnable application. This will all be created at runtime. My aim for this article is to provide a simple introduction into these 2 namespaces, you will not be an expert at the end of this article, but will have been exposed to enough, to realise what these 2 namespaces allow you to achieve.

    Why Would I Want To Create New Source Code And Applications At Runtime

    Well the reason that I started looking into this was dynamic code generation for Data Access Layers (DAL) /Business Access Layer (BAL) code based on an initial schema. So thats one possible area where it may be useful to create code at runtime, basically have an application create a bunch of auto generated source code files that can then be used within another project. Thats just where we (at work) found a use for this stuff.

    This led me onto investigating the the System.CodeDom.Compiler namespace classes, and as such I thought I would spend a bit of time talking about the possibilities that are available by using these classes.

    The rest of this article will be split roughly between a discussion about the System.CodeDom namespace, and the System.CodeDom.Compiler namespace. And finally a short discussion of what the attached demo application will be discussed.

    System.CodeDom

    The System.CodeDom namespace, contains classes, interface and enmerations that can be used to create source code at runtime. The general idea is that a newly constructed Document Object Model is being created, where methods, constructors using directives, variables are all creatable via using the System.CodeDom namespace. Where CodeDom really comes into its own is that it is lanuage agnostic and simply provides a CodeCompileUnit which can then be used by the System.CodeDom.Compiler namespace which uses this CodeCompileUnit to create the source code in any of the .NET languages

    I shall demonstrate a few examples of using the CodeDom.

    Creating Namespaces

    Collapse Copy Code
      CodeNamespace ns = new CodeNamespace("TestApp");
      ns.Imports.Add(new CodeNamespaceImport("System"));
      ns.Imports.Add(new CodeNamespaceImport("System.Text"));
      compileUnit.Namespaces.Add(ns);  
      

    Creating A Class

    Collapse Copy Code
      CodeTypeDeclaration ctd = new CodeTypeDeclaration(Name);
      ctd.IsClass = true;
      ctd.Attributes = MemberAttributes.Public;
      compileUnit.Namespaces[0].Types.Add(ctd); 
      

    Creating A Main Method

    Collapse Copy Code
      CodeEntryPointMethod method = new CodeEntryPointMethod();
      method.Attributes = MemberAttributes.Public |
      MemberAttributes.Static;
      ctd.Members.Add(method);
      

    Obviously this only gives you a very small example of what CodeDom is like to work with. I have to say the syntax is very verbose, but the fact that you can create any .NET source from CodeDom, makes it quite appealing. There are also some good wrappers around CodeDom, which shorten the syntax, I have included a list of related articles at the bottom of this article, should you wish to read around this subject a bit more.

    System.CodeDom.Compiler

    If we want to be able to use the System.CodeDom.Compiler namespace to compile the result of building a CodeDom object, we need to make sure that wherever we built our CodeDom object (using the syntax as shown above) that we return a CodeCompileUnit. It is by using this CodeCompileUnit that we are able to use the System.CodeDom.Compiler namespace, to create the source code in any of the .NET languages.

    For example this excerpt of the demo applications code, shows how we built a new source code file using the System.CodeDom and System.CodeDom.Compiler namespaces.

    Collapse Copy Code
    /// <summary>
    /// Generates the source code by calling the <see cref="CodeDomExample">GenerateCode</see> method
    /// </summary>
    private void picGenerate_Click(object sender, EventArgs e)
    {
    
        CodeDomProvider domProvider = (CodeDomProvider)getCodeEditorSyntaxOrProvdiderForLanguage
            (cmbPickLanguage.SelectedItem.ToString(),false);
    
        //create the code
        cde.GenerateCode(domProvider, cde.BuildSimpleAdder());
        // Display the generated source code file
        using (StreamReader sr = new StreamReader(getSourceFileName(domProvider)))
        {
            txtCode.Document.Text = sr.ReadToEnd();
            sr.Close();
        }
    }
    ....
    ....
    /// <summary>
    /// Returns either a SyntaxLanguage or a CodeDomProvider based on the selectedLanguage
    /// </summary>
    /// <param name="selectedLanguage">A string respresenting the selected language</param>
    /// <param name="syntaxObjectRequired">True if this method should return a SyntaxLanguage object</param>
    /// <returns></returns>
    private object getCodeEditorSyntaxOrProvdiderForLanguage(string selectedLanguage, bool syntaxObjectRequired)
    {
        switch (selectedLanguage)
        {
            case "CSharp":
                if (syntaxObjectRequired)
                    return SyntaxLanguage.CSharp;
                else
                    return CodeDomProvider.CreateProvider("CSharp");
            case "Visual Basic":
                if (syntaxObjectRequired)
                    return SyntaxLanguage.VBNET;
                else
                    return CodeDomProvider.CreateProvider("VisualBasic");
            default:
                if (syntaxObjectRequired)
                    return SyntaxLanguage.CSharp;
                else
                    return CodeDomProvider.CreateProvider("CSharp");
        }
    }
    ....
    ....
    /// <summary>
    /// Returns a string respresenting the filename for the generated app, which is based
    /// on the extension of the current <see cref="CodeDomProvider">CodeDomProvider</see>
    /// </summary>
    /// <param name="domProvider">The current <see cref="CodeDomProvider">CodeDomProvider</see></param>
    /// <returns>A string respresenting the filename for the generated app</returns>
    private string getSourceFileName(CodeDomProvider domProvider)
    {
        if (domProvider.FileExtension[0] == '.')
        {
            return "app" + domProvider.FileExtension;
        }
        else
        {
            return "app." + domProvider.FileExtension;
        }
    }
    ....
    ....
    /// <summary>
    /// Uses the CodeDom classes to create a simply
    /// built in run time source code file (graph). And returns
    /// a <see cref="CodeCompileUnit">CodeCompileUnit</see>
    /// that can be used by the <see cref="CompilerParameters">
    /// CompilerParameters</see> to build an actual 
    /// <see cref="Assembly">Assembly</see>
    /// </summary>
    /// <returns></returns>
    public CodeCompileUnit BuildSimpleAdder()
    {
    
        CodeCompileUnit compileUnit = new CodeCompileUnit();
        compileUnit.Namespaces.Add(InitializeNameSpace("TestApp"));
        CodeTypeDeclaration ctd = CreateClass("SimplePrint");
        // Add the class to the namespace
        compileUnit.Namespaces[0].Types.Add(ctd);
        CodeEntryPointMethod mtd = CreateMainMethod();
        ctd.Members.Add(mtd);
        CodeVariableDeclarationStatement VariableDeclaration =
            DeclareVariables(typeof(StringBuilder), "sbMessage");
        // Add the variable declaration to the method 
        mtd.Statements.Add(VariableDeclaration);
        //and print the results
        mtd.Statements.Add(new CodeSnippetExpression(
            "Console.WriteLine(sbMessage.Append(\"the result of adding (1+2) is \" + " +
            "(1+2).ToString()))"));
        // Build a call to System.Console.ReadLine, to keep console window alive to see results
        CodeTypeReferenceExpression csSystemConsoleType = 
            new CodeTypeReferenceExpression("System.Console");
        CodeMethodInvokeExpression csReadLine = 
            new CodeMethodInvokeExpression(csSystemConsoleType, "ReadLine");
    
        //// Add the ReadLine statement.
        mtd.Statements.Add(csReadLine);
    
        //lastly return it all
        return compileUnit;
    }
    ....
    ....
    /// <summary>
    /// Generates the code using either a CSharp or Visual Basic 
    /// CodeDomProvider. This generated code uses the 
    /// <see cref="CodeCompileUnit">CodeCompileUnit</see> that was created
    /// by the BuildSimpleAdder method
    /// </summary>
    /// <param name="domProvider">The CodeDomProvider to use, CSharp or Visual Basic CodeDomProviders in our case</param>
    /// <param name="compileunit">A <see cref="CodeCompileUnit">CodeCompileUnit</see> that can be used by
    /// the System.CodeDom.Compiler classes</param>
    public void GenerateCode(CodeDomProvider domProvider, CodeCompileUnit compileunit)
    {
        //builds the source based on the selected language
        String srcFile;
        if (domProvider.FileExtension[0] == '.')
        {
            srcFile = "app" + domProvider.FileExtension;
        }
        else
        {
            srcFile = "app." + domProvider.FileExtension;
        }
        //we want a nice indemtable output file
        using (IndentedTextWriter tw = new IndentedTextWriter(new StreamWriter(srcFile, false), "    "))
        {
            // Create the source code
            domProvider.GenerateCodeFromCompileUnit(compileunit, tw, new CodeGeneratorOptions());
            tw.Close();
        }
    }
    

    So doing this is enough to create a new source code file, in any of the .NET languages. This is all thanks for the CodeDomProvider class, which is able to create providers for all of the .NET languages. So providing we use the the relevant CodeDomProvider for the CodeCompileUnit that came out of using CodeDom can be generated into a source code any of the .NET languages. Neat Huh.

    So what have we got so far, well we create a DOM representing a new class, which eventually gave us a CodeCompileUnit that we then used to create the relevant source code by using the specfic e CodeDomProvider class, for the language we wanted to generate.

    So thats cool, we have a source code file. But at the top of this article I also said that I would show you how to compile source code into an Assembly or an Exe. So lets continue to look at that.

    Again I think the best thing to show you is the relavant source code.

    Collapse Copy Code
    /// <summary>
    /// Compile the source code by calling the <see cref="CodeDomExample">Compile</see> method
    /// </summary>
    private void picCompile_Click(object sender, EventArgs e)
    {
        CodeDomProvider domProvider = (CodeDomProvider)getCodeEditorSyntaxOrProvdiderForLanguage
            (cmbPickLanguage.SelectedItem.ToString(), false);
        // Compile the source file into an executable output file.
        string srcFile = getSourceFileName(domProvider);
        CompilerResults cr = cde.Compile(domProvider,srcFile,"app.exe");
        string message = string.Empty;
    
        if (cr.Errors.Count > 0)
        {
            // Display compilation errors.
            message+= "Errors encountered while building " +
                            srcFile + " into " + cr.PathToAssembly + ": \r\n\n";
            foreach (CompilerError ce in cr.Errors)
                message +=ce.ToString() + "\r\n";
            picRun.Enabled = false;
            MessageBox.Show(message);
        }
        else
        {
            message += "Source " + srcFile + " built into " +
                            cr.PathToAssembly + " with no errors.";
            picRun.Enabled = true;
            MessageBox.Show(message);
        }
    }
    ....
    ....
    /// <summary>
    /// Returns either a SyntaxLanguage or a CodeDomProvider based on the selectedLanguage
    /// </summary>
    /// <param name="selectedLanguage">A string respresenting the selected language</param>
    /// <param name="syntaxObjectRequired">True if this method should return a SyntaxLanguage object</param>
    /// <returns></returns>
    private object getCodeEditorSyntaxOrProvdiderForLanguage(string selectedLanguage, bool syntaxObjectRequired)
    {
        switch (selectedLanguage)
        {
            case "CSharp":
                if (syntaxObjectRequired)
                    return SyntaxLanguage.CSharp;
                else
                    return CodeDomProvider.CreateProvider("CSharp");
            case "Visual Basic":
                if (syntaxObjectRequired)
                    return SyntaxLanguage.VBNET;
                else
                    return CodeDomProvider.CreateProvider("VisualBasic");
            default:
                if (syntaxObjectRequired)
                    return SyntaxLanguage.CSharp;
                else
                    return CodeDomProvider.CreateProvider("CSharp");
        }
    }
    ....
    ....
    /// <summary>
    /// Returns a string respresenting the filename for the generated app, which is based
    /// on the extension of the current <see cref="CodeDomProvider">CodeDomProvider</see>
    /// </summary>
    /// <param name="domProvider">The current <see cref="CodeDomProvider">CodeDomProvider</see></param>
    /// <returns>A string respresenting the filename for the generated app</returns>
    private string getSourceFileName(CodeDomProvider domProvider)
    {
        if (domProvider.FileExtension[0] == '.')
        {
            return "app" + domProvider.FileExtension;
        }
        else
        {
            return "app." + domProvider.FileExtension;
        }
    }
    ....
    ....
    /// <summary>
    /// Uses the <see cref="CompilerParameters">CompilerParameters</see>
    /// to compile the the source file, creating the output file
    /// </summary>
    /// <param name="domProvider">The CodeDomProvider to use, CSharp or Visual Basic CodeDomProviders in our case</param>
    /// <param name="srcFile">The source file</param>
    /// <param name="exeFile">The name for the output file</param>
    /// <returns>The actual <see cref="CompilerResults">CompilerResults</see>
    /// which will holds the compiled <see cref="Assembly">Assembly</see></returns>
    public CompilerResults Compile(CodeDomProvider domProvider, String srcFile,String exeFile)
    {
        // Configure a CompilerParameters that links System.dll
        // and produces the specified executable file.
        String[] referenceAssemblies = { "System.dll" };
        CompilerParameters cp = new CompilerParameters(referenceAssemblies,exeFile, false);
        //make sure we create an EXE not a Dll, and then compile
        cp.GenerateExecutable = true;
        CompilerResults compiledResults = domProvider.CompileAssemblyFromFile(cp, srcFile);
        return compiledResults;
    }
    

    And that is enough to get us a EXE created for the source code that we created earlier. Remember this is all being done at runtime, I think thats pretty cool actually. Create a new source code and compile and run it at runtime. That's neat.

    The DEMO Application

    Anyway, lets just have a quick chat about the demo app. I use the fantastic Fireball code highlighter, available right here at Codeproject. And the basic program that I am trying to create at runtime is as follows

    Collapse Copy Code
    Namespace TestApp {
        using System;
        using System.Text;
        
        
        Public Class SimplePrint {
            
            Public Static void Main() {
                System.Text.StringBuilder sbMessage = new System.Text.StringBuilder();
                Console.WriteLine(sbMessage.Append("the result of adding (1+2) is " + (1+2).ToString()));
                System.Console.ReadLine();
            }
        }
    }
    

    Which when generated in Visual Basic .NET, looks as follows:

    Collapse Copy Code
    Option Strict Off
    Option Explicit On
    
    Imports System
    Imports System.Text
    
    Namespace TestApp
        
        Public Class SimplePrint
            
            Public Shared Sub Main()
                Dim sbMessage As System.Text.StringBuilder = New System.Text.StringBuilder
                Console.WriteLine(sbMessage.Append("the result of adding (1+2) is " + (1+2).ToString()))
                System.Console.ReadLine
            End Sub
        End Class
    End Namespace
    

    And the demo application looks like this, where there are 3 buttons:

    • Generate button : generates the source code
    • Compile button : compiles the source code
    • Run : runs the newly compiled app

    Here is a screen shot of the demo app, just after a generate and compile being performed, where the selected .NET language was Visual Basic

    And here is the actual newly created application runnning

    And thats about it. Like I say, you are by no means an expert from reading this, but I hope its given you an idea about what can be done with these 2 very cool namespaces.

    Other CodeDom Resources

    msdn2.microsoft.com/en-us/library/system.codedom.aspx

    msdn2.microsoft.com/en-us/library/system.codedom.compiler(VS.71).aspx

    http://msdn2.microsoft.com/en-us/library/system.codedom.compiler.codedomprovider.aspx

    codedom_assistant.aspx

    refly.aspx

    http://www.codeproject.com/KB/recipes/codedomparser.aspx

    http://www.codeproject.com/KB/architecture/codedompatterns.aspx#CodePatternCompileUnit

    http://www.codeproject.com/KB/database/ObjectMapping2.aspx

    Future Work

    I may end up elaborating on this article in the fiture to discuss how the process of code generation can be handled more efficienly using some of the Visual Studio SDK tools.

    History

    27/01/08 : Initial Issue

    License

    About the Author

    Sacha Barber


    Member
    I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)

    - MSc (Passed with distinctions), in Information Technology for E-Commerce
    - BSc Hons (1st class) in Computer Science & Artificial Intelligence

    Both of these at Sussex University UK.

    Award(s)

    I am lucky enough to have won a few awards for Zany Crazy code articles over the years

    • Microsoft C# MVP 2009
    • Codeproject MVP 2009
    • Microsoft C# MVP 2008
    • Codeproject MVP 2008
    • And numerous codeproject awards which you can see over at my blog

    Describes a collection of WebReference objects.


    By Code Collector
    Printer Friendly Version
    View My FAQ's

        
    References:  Initialize, Read, Create, Generate, Import, Main, Compile, Print, CollectionBase, CodeCompileUnit, CodeNamespace, CodeDomProvider, Report, WebReferenceOptions

    Describes a collection of WebReference objects.


    public sealed class WebReferenceCollection : CollectionBase
    using System; using System.CodeDom; using System.CodeDom.Compiler; using System.Security.Permissions; using System.Web.Services; using System.Web.Services.Description; using System.Web.Services.Discovery; using System.Xml; using System.Xml.Serialization; class Test { [SecurityPermissionAttribute(SecurityAction.Demand, Unrestricted=true)] static void Run(){ // Get a WSDL file describing a service. ServiceDescription description = ServiceDescription.Read("DataTypes_CS.wsdl"); // Initialize a service description importer. ServiceDescriptionImporter importer = new ServiceDescriptionImporter(); importer.ProtocolName = "Soap12"; // Use SOAP 1.2. importer.AddServiceDescription(description,null,null); // Report on the service descriptions. Console.WriteLine("Importing {0} service descriptions with {1} associated schemas.", importer.ServiceDescriptions.Count, importer.Schemas.Count); // Generate a proxy client. importer.Style = ServiceDescriptionImportStyle.Client; // Generate properties to represent primitive values. importer.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateProperties; // Initialize a Code-DOM tree into which we will import the service. CodeNamespace nmspace = new CodeNamespace(); CodeCompileUnit unit1 = new CodeCompileUnit(); unit1.Namespaces.Add(nmspace); // Import the service into the Code-DOM tree. This creates proxy code // that uses the service. ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit1); if (warning == 0) { // Generate and print the proxy code in C#. CodeDomProvider provider1 = CodeDomProvider.CreateProvider("CSharp"); provider1.GenerateCodeFromCompileUnit(unit1, Console.Out, new CodeGeneratorOptions()); } else { // Print an error message. Console.WriteLine("Warning: " + warning); } string url = "AddNumbers.wsdl"; // Read in a WSDL service description. XmlTextReader reader = new XmlTextReader(url); ServiceDescription wsdl = ServiceDescription.Read(reader); // Create a WSDL collection. DiscoveryClientDocumentCollection wsdlCollection = new DiscoveryClientDocumentCollection(); wsdlCollection.Add(url, wsdl); // Create a namespace and a unit for compilation. CodeNamespace space = new CodeNamespace(); CodeCompileUnit unit = new CodeCompileUnit(); unit.Namespaces.Add(space); // Create a web referernce using the WSDL collection. WebReference reference = new WebReference(wsdlCollection, space); reference.ProtocolName = "Soap12"; // Print some information about the web reference. Console.WriteLine("Base Url = {0}", reference.AppSettingBaseUrl); Console.WriteLine("Url Key = {0}", reference.AppSettingUrlKey); Console.WriteLine("Documents = {0}", reference.Documents.Count); // Create a web reference collection. WebReferenceCollection references = new WebReferenceCollection(); references.Add(reference); // Compile a proxy client and print out the code. CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp"); WebReferenceOptions options = new WebReferenceOptions(); options.Style = ServiceDescriptionImportStyle.Client; options.CodeGenerationOptions = CodeGenerationOptions.GenerateNewAsync; ServiceDescriptionImporter.GenerateWebReferences( references, provider, unit, options ); provider.GenerateCodeFromCompileUnit(unit, Console.Out, new CodeGeneratorOptions() ); } static void Main () { Test.Run(); } }

    Biography - Code Collector
    Code collector scours the internet collecting a wide variety of code snippets for our members.

    Describes a collection of WebReference objects.
    Describes a collection of WebReference objects.
    CollectionBase, WebReferenceCollection
    By on 11/3/2009 6:36:15 PM.

    转载自:http://www.eggheadcafe.com/sample-code/csharp.NET/37279506-5118-4afe-aada-ae0251509e14/describes-a-collection-of.aspx

    If you write applications in .NET that generate .NET language source-code as output, and the output language should be selectable (typically C# or VB.NET), then you will probably end up generating the output from a System.CodeDom graph. Once you have the CodeDOM the actual code generation support in .NET is easy, clean and produces reasonable code. So what's the catch? Well, consider at least the following:

    • Building CodeDOMs programmatically is a real pain - the .NET API's are convoluted, difficult to understand, error-prone and you often require many lines of code to generate one line of code in the CodeDOM. (Reminds me of the days I used to program in assembler..). For this reason, many people have gone to great pains to abstract the CodeDOM API's into more meaningful, much easier to use, and generally more efficient class libraries. I reference a few of these from CodeProject below:
    • Some of the constructs that you prefer to code yourself just cannot be reproduced in a CodeDOM, and require that you be a lot more creative and defensive in your approach when programmatically building CodeDOMs.

    Another approach is to find or build a System.CodeDom.Compiler.ICodeParser implementation for the input.NET language you are generating CodeDOMs from. This allows you to write code in that .NET language, which is then parsed to produce a System.CodeDom.CodeCompileUnit (CodeDOM). Once you have the CodeDOM it is trivial to generate the code (see the CodeGeneration.GenerateCode method below). But again, there is no free-lunch - many ICodeParser implementations exist, but all of them (in my experience) are trivial solutions, mainly geared to generating code for class-interfaces or web-service interfaces.

    Enter IC#Code and their #Develop (SharpDevelop) product.

    As part of this product, they ship an assembly - ICSharpCode.NRefactory.dll  (and you can build the source code) which provides a fairly comprehensive ICodeParser implementation. Using the CodeDOMVisitor 'visitor' object, it is easy to generate source-code from a CodeDOM created by parsing source-code, as demonstrated in the code below. Note, though, that as before your input source-code will have to be very standard (no funny stuff), and there are some quirks with the CodeDOMVisitor object (which includes some issues with class constructor generation, and some of the looping constructs). In general the results are pleasing, and I look forward to future updates to this assembly. Interestingly, they also provide other 'visit-ations', including a working C#-to-VB.NET converter.

    The code below was written for VS2005/.NET 2.0 and uses the #Develop 2.0.0.1462RC2 version source-code and DLL's. You will need to add a reference in your project to the ICSharpCode.NRefactory.dll assembly to get your project to build.

    CodeGenerator Classes for .NET 2.0
    using System;
    using System.CodeDom;
    using System.CodeDom.Compiler;
    using System.Collections.Generic;
    using System.Text;
    using System.IO;
    using ICSharpCode.NRefactory.Parser;
    namespace CodeGeneration
    {
      public class CodeGenerator
      {
        private ICodeParser parser;
        public ICodeParser Parser
        {
          get { return parser; }
          set { parser = value; }
        }
        private CodeDomProvider provider;
        public CodeDomProvider Provider
        {
          get { return provider; }
          set { provider = value; }
        }
        private CodeGeneratorOptions options;
        public CodeGeneratorOptions Options
        {
          get { return options; }
          set { options = value; }
        }
        protected virtual CodeGeneratorOptions 
          GetDefaultOptions()
        {
          CodeGeneratorOptions options = 
            new CodeGeneratorOptions();
          options.BracingStyle = "C";
          options.BlankLinesBetweenMembers = false;
          options.IndentString = "\t";
          return options;
        }
        public virtual void GenerateCode(TextReader reader, 
          TextWriter writer)
        {
          CodeCompileUnit codeCompileUnit = Parser.Parse(reader);
          Provider.GenerateCodeFromCompileUnit(codeCompileUnit, writer, Options);
          reader.Close();
          // Important to flush the output stream.
          writer.Flush();
          writer.Close();
        }
        public CodeGenerator(ICodeParser parser, 
          CodeDomProvider provider)
        {
          Options = GetDefaultOptions();
          Parser = parser;
          Provider = provider;
        }
        public CodeGenerator(ICodeParser parser, 
          CodeDomProvider provider,
          CodeGeneratorOptions options)
        {
          Options = options;
          Parser = parser;
          Provider = provider;
        }
      }
      public class Parser : ICodeParser
      {
        #region ICodeParser Members
        public CodeCompileUnit Parse(TextReader codeStream)
        {
          // Set the parser for the correct language.
          IParser parser = ParserFactory.CreateParser(Language,
            codeStream);
          parser.Parse();
          // Use a CodeDom visitor to gen. a CodeCompileUnit.
          CodeDOMVisitor visit = new CodeDOMVisitor();
          CodeNamespace globalNamespace =  (CodeNamespace)
            visit.Visit(parser.CompilationUnit, null);
          // Mostly, you need to remove the "Global"
          // code namespace from the compile unit.
          visit.codeCompileUnit.Namespaces.Remove(globalNamespace);
          return visit.codeCompileUnit;
        }
        #endregion
        private SupportedLanguage language = SupportedLanguage.CSharp;
        public SupportedLanguage Language
        {
          get { return language; }
          set { language = value; }
        }
        public Parser(SupportedLanguage language)
        {
          Language = language;
        }
      }
    }
    posted on Monday, July 24, 2006 8:55 AM

    http://geekswithblogs.net/willemf/archive/2006/07/24/86075.aspx

    C# 3.0 and CodeDOM

    The CodeDOM is a very handy .NET API which allows you to programatically compile code using the .NET compilers and programatically construct code without just pasting together strings. 

    With the new version of the language, we've heard a numer of questions about how to use the CodeDOM with the new compiler.

    There are two aspects to the inegration of C#3.0 with CodeDOM:

    • Programatically compiling C# source code: This is supported in .NET3.5.  The existing CodeDOM is augmented with an overload of CSharpCodeProvider which takes a "providerOptions" argument.  This can be used to point CodeDOM at the new .NET Framework 3.5 C# compiler (which supports C#3.0), by passing a "providerOptions" dictionary containing "CompilerVersion" as "v3.5".  This can also be controlled via the .config file, which is done  for example in Orcas ASP.NET websites targeting .NET3.5. 

    • Programatically constructing C#3.0 source code:  There won't be support for the this in the .NET Framework 3.5 CodeDOM that ships with Orcas.  Luckily, very few of the C# 3.0 features need CodeDOM support - since most new features are expressions, and the CodeDOM doesn't go down to the expression level. 
    Example of programatically compiling C#3.0 source code:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.CSharp;
    using System.CodeDom.Compiler;
    class Program
    {
        static void Main(string[] args)
        {
            var csc = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } });
            var parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll" }, "foo.exe", true);
            parameters.GenerateExecutable = true;
            CompilerResults results = csc.CompileAssemblyFromSource(parameters,
            @"using System.Linq;
                class Program {
                  public static void Main(string[] args) {
                    var q = from i in Enumerable.Rnge(1,100)
                              where i % 2 == 0
                              select i;
                  }
                }"
    );
            results.Errors.Cast<CompilerError>().ToList().ForEach(error => Console.WriteLine(error.ErrorText));
        }
    }

    转载自:http://blogs.msdn.com/lukeh/archive/2007/07/11/c-3-0-and-codedom.aspx
  • 相关阅读:
    公司技术部与其他部门之间的那些事儿
    5万元百元大钞的"渣渣钱"重新拼接的软件方面的解决办法的思路。
    公司技术部门内部的发展变化过程。
    手机开发与360的那点事儿
    通用快排
    被中断的函数
    setjmp与longjmp
    setjmp在非主函数中调用
    array and structure
    check your input
  • 原文地址:https://www.cnblogs.com/wuhenke/p/1625585.html
Copyright © 2011-2022 走看看