1

I need compile and execute code via CSharpCodeProvider int the current context, for example:

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

namespace ConsoleApplication1
{
    public class Program
    {
        public static void WriteMessage(string message)
        {
            Console.WriteLine(message);
        }

        static void Main(string[] args)
        {
            var compiler = new CSharpCodeProvider();
            var parms = new CompilerParameters
            {
                GenerateExecutable = false,
                GenerateInMemory = true,
            };

            parms.ReferencedAssemblies.Add("System.dll");

            var results = compiler.CompileAssemblyFromSource(parms, new string[]
            {@" using System;

                class MyClass
                {
                    public void Message(string message)
                    {
                        Program.WriteMessage(message);//Console.Write(message);
                    }               
                }"});

            if (results.Errors.Count == 0)
            {
                var myClass = results.CompiledAssembly.CreateInstance("MyClass");
                myClass.GetType().
                    GetMethod("Message").
                    Invoke(myClass, new[] {"Hello World!"});
            }
            else
            {
                foreach (var error in results.Errors)
                {
                    Console.WriteLine(error);
                }
            }
            Console.Read();
        }
    }
}

How you can see, i try to call Program.WriteMessage from the compiled code but i only get errors. Why?

Domi
  • 22,151
  • 15
  • 92
  • 122
l1pton17
  • 444
  • 4
  • 16
  • what errors? post the errors!! I also see no reference to program.write message – Ahmed ilyas Dec 01 '13 at 13:04
  • By the way, the "context" in .NET-world is called your [AppDomain](http://msdn.microsoft.com/en-us/library/system.appdomain(v=vs.110).aspx). – Domi Dec 01 '13 at 13:19

1 Answers1

2

The problem is that your compiled program tries to use a class (Program) from the current AppDomain, but when compiling, it does not know anything about it. In order to link the Program class and all other classes of the "compiling program" into the "compiled program", you need to add the current AppDomain's assembly (or, as the code below does, all assemblies) to the reference libraries before compiling your code. This answer tells you how to:

  1. link the current AppDomain into the compiled program and then
  2. load the program into the current AppDomain.

Specifically, you are missing this part for step 1:

    foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
    {
        try
        {
            string location = assembly.Location;
            if (!String.IsNullOrEmpty(location))
            {
                compilerParams.ReferencedAssemblies.Add(location);
            }
        }
        catch (NotSupportedException)
        {
            // this happens for dynamic assemblies, so just ignore it. 
        }
    } 

where compilerParams is your instance of CompilerParameters. You call it parms in your code.

Community
  • 1
  • 1
Domi
  • 22,151
  • 15
  • 92
  • 122