Runtime Csv Exporter using Dapper

Today I decided to create a run-time compiled Csv generator and compare it to a compile-time version of the same code. It works a treat with little noticeable difference in performance over 10000 runs (of a very small table)

These are the compile time definitions:

public class Client
{
    public long id { get; set; }
    public string forenames { get; internal set; }
    public string surname { get; set; }
    public long Office_id { get; set; }
}

public interface IExport
{
    void Export(IDbConnection openConnection);
}

public class Exporter : IExport
{
    public void Export(IDbConnection openConnection)
    {
        var results = openConnection
            .Query<Client>("SELECT * FROM Client");

        foreach (Client client in results)
        {
            string line =
                client.id.ToString() + ',' +
                client.forenames.ToString() + ',' +
                client.surname.ToString() + ',' +
                client.Office_id.ToString();
        }
    }
}

This is the string constant duplicate of the same code:

public const string ClassText = @"
    public class Exporter : IExport
    {
        public void Export(IDbConnection openConnection)
        {
            var results = openConnection
                .Query<Client>(""SELECT * FROM Client"");

            foreach (Client client in results)
            {
                string line =
                    client.id.ToString() + ',' +
                    client.forenames.ToString() + ',' +
                    client.surname.ToString() + ',' +
                    client.Office_id.ToString();
            }
        }

        public class Client
        {
            public long id { get; set; }
            public string forenames { get; internal set; }
            public string surname { get; set; }
            public long Office_id { get; set; }
        }
    }";

This is the code that compiles the string into a type:

public static Type ClassFromString(string classStr, string className)
{
    CompilerParameters cp = new CompilerParameters();
    cp.ReferencedAssemblies.Add("dapper.dll");
    cp.ReferencedAssemblies.Add("system.dll");
    cp.ReferencedAssemblies.Add("system.data.dll");
    cp.ReferencedAssemblies.Add(
        typeof(IExport).Assembly.GetModules()[0].FullyQualifiedName);
    cp.GenerateExecutable = false;
    cp.GenerateInMemory = true;
    cp.IncludeDebugInformation = false;

    StringBuilder code = new StringBuilder();
    code.Append("using Dapper; using System; using System.Data; " +
        "using System.Data.SqlClient; using CsvOut; ");
    code.Append(classStr);
    CompilerResults cr;
    CodeDomProvider prov = null;
    prov = CodeDomProvider.CreateProvider("cs");

    cr = prov.CompileAssemblyFromSource(cp, code.ToString());
    if (cr.Errors.HasErrors)
    {
        var e = new InvalidOperationException("Error Compiling Expression");
        foreach (CompilerError err in cr.Errors)
        {
            e = new InvalidOperationException(
                string.Format("Line {0}: {1}n", err.Line, err.ErrorText),
                e);
        }

        throw e;
    }

    return cr.CompiledAssembly.GetType(className, true, true);
}

And this was the final version of the timing code:

class Program
{
    static void Main(string[] args)
    {
        IExport compiletime = Activator
            .CreateInstance(Type.GetType("CsvOut.Exporter")) as IExport;
        IExport runtime = Activator
            .CreateInstance(ClassFromString(ClassText, "Exporter")) as IExport;
        CallIt(compiletime, 10);
        CallIt(runtime, 10);

        Console.Write(CallIt(compiletime, 10000));
        Console.Write("  ");
        Console.Write(CallIt(runtime, 10000));

        Console.ReadKey();
    }

    static long CallIt(IExport instance, int count)
    {
        IDbConnection connection;
        connection = new SqlConnection("...");
        connection.Open();

        Stopwatch timer = new Stopwatch();
        timer.Start();
        for (int i = 0; i < count; i++)
        {
            instance.Export(connection);
        }
        timer.Stop();
        return timer.ElapsedMilliseconds;
    }
}