Search code examples
c#dynamiccompilationcodedomruntime-compilation

dynamic keyword in string input during CodeDom compilation


in order to convert string to code I was using the CodeDom compiler.
I am talking about Compiling C# Code at Runtime!
Especially I want to make Runtime Compilation with several parameters which types can be different.

    using System;
    using System.CodeDom;
    using System.CodeDom.Compiler;
    using System.Collections.Generic;
    using System.Data;
    using System.Diagnostics;
    using System.Dynamic;
    using System.Net;
    using System.Reflection;
    using Microsoft.CSharp;

    static void Main()
    {
         String2LineOfCommand("P[0].ToString() + P[1].ToString()", new [] { 2, 4});
    }

    private void String2LineOfCommand(string expresion1, params object[] P)
    {
        MethodInfo function = CreateFunction(expresion1);
        object result = function.Invoke(null, P);
        Console.WriteLine(result.ToString());
    }

    public static MethodInfo CreateFunction(string function)
    {
        string code1 = @"
                        using System;
                        using System.Collections.Generic;
                        using System.Reflection;
                        using System.Dynamic;

                        namespace UserFunctions
                        {                
                            public class ParametricFunctions
                            {                
                                  public static object Function1(params int[] P)
                                  {
                                       return " +  function + @";
                                  }
                             }
                         }
                       ";

        var providerOptions = new Dictionary<string, string>();
        providerOptions.Add("CompilerVersion", "v4.0");

        CSharpCodeProvider provider = new CSharpCodeProvider(providerOptions);
        CompilerParameters cp = new CompilerParameters();
        cp.GenerateInMemory = true;
        cp.TreatWarningsAsErrors = false;
        cp.ReferencedAssemblies.Add("System.dll");
        cp.ReferencedAssemblies.Add("System.Core.dll");
        cp.ReferencedAssemblies.Add("System.Windows.dll");
        cp.ReferencedAssemblies.Add("System.Dynamic.dll");

        CompilerResults results = provider.CompileAssemblyFromSource(cp, code1);

        Type parametricFunction1 = results.CompiledAssembly.GetType("UserFunctions.ParametricFunctions");
        return parametricFunction1.GetMethod("Function1");
    }

This code works just fine!
But as I told you before I am not talking about int type parameters.
I am talking about different types of input parameters in different situations at runtime!

If I will type

     String2LineOfCommand("P[0].ToString() + P[1].ToString()", 2, 4);

Instead of

     String2LineOfCommand("P[0].ToString() + P[1].ToString()", new [] { 2, 4});

Then I will get an error message:

   An unhandled exception of type 'System.Reflection.TargetParameterCountException' occurred in mscorlib.dll
   Additional information: Parameter count mismatch.

Please tell me why?

Also look inside...

       public static MethodInfo CreateFunction(string function)  

When I am trying to type

       public static object Function1(params object[] P) 

instead of

       public static object Function1(params int[] P)

It shows me an error message:

      An unhandled exception of type 'System.ArgumentException' occurred in mscorlib.dll
      Additional information: Object of type 'System.Int32[]' cannot be converted to type 'System.Object[]'.  

But when I am trying to type

      public static object Function(params dynamic[] P)  

compilation fails and there is no message about error!
I think I am missing a reference!
dynamic keyword is available for .net 4.0
I already wrote:

      providerOptions.Add("CompilerVersion", "v4.0");

But no result!

PLEASE help me!


Solution

  • The CompilerResults class has an Errors property. The errors for which the compilation fails are there.

    Code so that it works with dynamic (or object, I don't see the point of dynamic here):

    using System;
    using System.CodeDom.Compiler;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Reflection;
    using Microsoft.CSharp;
    
    public class Program
    {
    
        static void Main()
        {
            String2LineOfCommand("P[0].ToString() + P[1].ToString()", 2, 4);
        }
    
        private static void String2LineOfCommand(string expresion1, params dynamic[] P)
        {
            MethodInfo function = CreateFunction(expresion1);
            object result = function.Invoke(null, new[] { P });
            Console.WriteLine(result.ToString());
            Debug.WriteLine(result.ToString());
        }
    
        public static MethodInfo CreateFunction(string function)
        {
            string code1 = @"
                            using System;
                            using System.Collections.Generic;
                            using System.Reflection;
                            using System.Dynamic;
    
                            namespace UserFunctions
                            {                
                                public class ParametricFunctions
                                {                
                                      public static object Function1(dynamic[] P)
                                      {
                                           return " + function + @";
                                      }
                                 }
                             }
                           ";
    
            var providerOptions = new Dictionary<string, string>();
            providerOptions.Add("CompilerVersion", "v4.0");
    
            CSharpCodeProvider provider = new CSharpCodeProvider(providerOptions);
            CompilerParameters cp = new CompilerParameters();
            cp.GenerateInMemory = true;
            cp.TreatWarningsAsErrors = false;
            cp.ReferencedAssemblies.Add("System.dll");
            cp.ReferencedAssemblies.Add("System.Core.dll");
            cp.ReferencedAssemblies.Add("System.Windows.dll");
            cp.ReferencedAssemblies.Add("System.Dynamic.dll");
            cp.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
    
            CompilerResults results = provider.CompileAssemblyFromSource(cp, code1);
    
            Type parametricFunction1 = results.CompiledAssembly.GetType("UserFunctions.ParametricFunctions");
            return parametricFunction1.GetMethod("Function1");
        }
    }