views:

924

answers:

2

Is CompileAssemblyFromDom faster than CompileAssemblyFromSource?

It should be as it presumably bypasses the compiler front-end.

A: 

I've tried finding the ultimate compiler call earlier and I gave up. There's quite a number of layers of interfaces and virtual classes for my patience.

I don't think the source reader part of the compiler ends up with a DOM tree, but intuitively I would agree with you. The work necessary to transform the DOM to IL should be much less than reading C# source code.

Lasse V. Karlsen
+5  A: 

CompileAssemblyFromDom compiles to a .cs file which is then run through the normal C# compiler.

Example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.CSharp;
using System.CodeDom;
using System.IO;
using System.CodeDom.Compiler;
using System.Reflection;

namespace CodeDomQuestion
{
    class Program
    {

        private static void Main(string[] args)
        {
            Program p = new Program();
            p.dotest("C:\\fs.exe");
        }

        public void dotest(string outputname)
        {
            CSharpCodeProvider cscProvider = new CSharpCodeProvider();
            CompilerParameters cp = new CompilerParameters();
            cp.MainClass = null;
            cp.GenerateExecutable = true;
            cp.OutputAssembly = outputname;

            CodeNamespace ns = new CodeNamespace("StackOverflowd");

            CodeTypeDeclaration type = new CodeTypeDeclaration();
            type.IsClass = true;
            type.Name = "MainClass";
            type.TypeAttributes = TypeAttributes.Public;

            ns.Types.Add(type);

            CodeMemberMethod cmm = new CodeMemberMethod();
            cmm.Attributes = MemberAttributes.Static;
            cmm.Name = "Main";
            cmm.Statements.Add(new CodeSnippetExpression("System.Console.WriteLine('f'zxcvv)"));
            type.Members.Add(cmm);

            CodeCompileUnit ccu = new CodeCompileUnit();
            ccu.Namespaces.Add(ns);

            CompilerResults results = cscProvider.CompileAssemblyFromDom(cp, ccu);

            foreach (CompilerError err in results.Errors)
                Console.WriteLine(err.ErrorText + " - " + err.FileName + ":" + err.Line);
            Console.WriteLine();
        }
    }
}

which shows errors in a (now nonexistent) temp file:

) expected - c:\Documents and Settings\jacob\Local Settings\Temp\x59n9yb-.0.cs:17

; expected - c:\Documents and Settings\jacob\Local Settings\Temp\x59n9yb-.0.cs:17

Invalid expression term ')' - c:\Documents and Settings\jacob\Local Settings\Tem p\x59n9yb-.0.cs:17

So I guess the answer is "no"

Jacob
Absolutely correct, albeit disappointing. CodeDOM is converted into C# text, saved to a temporary file, and then the C# compiler (which is developed in C++) is called. I don't know if this is the case for Mono, but sadly the CodeDOM is actually slower than writing C# directly.
David Pfeffer
Supposedly csc.exe is being rewritten in C#, so in the future there may be a managed way that lets you pass an AST directly to the compiler. However, as .NET 3.5 stands now, there is currently no way to bypass the compiler frontend other than emitting the IL assembly or bytecode yourself.
Jacob