Взаимодействие со сборкой, созданной CSharpCodeProvider

Я сделал игрушечный компилятор для обучения/экспериментов.

Вот код для компиляции кода C#:

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

namespace ProgrammingSystem
{
    public class Compiler
    {
        public Program Compile(Code code)
        {
            string template = @"
public class C 
{
    public static void Main(string[] args) 
    { 
        [[Source]] 
    } 
}";

            string source = template.Replace("[[Source]]", code.Source);

            CodeDomProvider compiler = new CSharpCodeProvider();

            CompilerParameters parameters = new CompilerParameters();
            parameters.WarningLevel = 4;
            parameters.GenerateExecutable = false;
            parameters.GenerateInMemory = true;

            CompilerResults r = compiler.CompileAssemblyFromSource(parameters, source);
            foreach (var item in r.Output)
                this.Fire(Output, item);            

            Assembly assembly = r.CompiledAssembly;

            return new Program(assembly);
        }

        public event EventHandler<OutputEventArgs> Output;
    }
}

А вот код для запуска скомпилированного кода:

using System;
using System.Reflection;

namespace ProgrammingSystem
{
    public class Program
    {
        private System.Reflection.Assembly assembly;

        public Program(System.Reflection.Assembly assembly)
        {
            this.assembly = assembly;
        }

        public event EventHandler<OutputEventArgs> ProgramOutput;

        public void Run()
        {
            Type[] types = this.assembly.GetTypes();
            Type programType = types[0];
            MethodInfo programMainMethod = programType.GetMethod("Main");
            programMainMethod.Invoke(null, new object[] { new string[] { } });

            this.Fire(ProgramOutput, "hello");
        }
    }
}

Какими средствами я могу взаимодействовать с типом, созданным во время выполнения CSharpCodeProvider?

В частности, я заинтересован либо в подписке на общедоступный делегат, либо в захвате стандартного вывода, но общей информации о том, как типы могут общаться друг с другом в такой ситуации, будет достаточно.


person Aaron Anodide    schedule 28.09.2012    source источник
comment
можно использовать базу или интерфейс   -  person Andras Zoltan    schedule 29.09.2012
comment
Хорошо, интерфейс обратного вызова - это более простое решение, чем мое, потому что мне не пришлось бы проходить через все обручи отражения делегата...   -  person Aaron Anodide    schedule 29.09.2012


Ответы (1)


Я понял это, используя документацию здесь .

using System;
using System.Reflection;

namespace ProgrammingSystem
{
    public class Program
    {
        private System.Reflection.Assembly assembly;

        public Program(System.Reflection.Assembly assembly)
        {
            this.assembly = assembly;
        }

        public event EventHandler<OutputEventArgs> ProgramOutput;

        public void Run()
        {
            Type programType = this.assembly.GetType("C");
            object program = Activator.CreateInstance(programType);
            EventInfo outputEvent = programType.GetEvent("output");
            Delegate delegateInstance = Delegate.CreateDelegate(
                                                    outputEvent.EventHandlerType, this,
                                                    typeof(Program).GetMethod("OutputHandler", BindingFlags.NonPublic | BindingFlags.Instance));
            MethodInfo addHandlerMethod = outputEvent.GetAddMethod();
            addHandlerMethod.Invoke(program, new [] { delegateInstance });

            programType.GetMethod("Run").Invoke(program, null);
        }

        private void OutputHandler(string s)
        {
            this.Fire(ProgramOutput, s);
        }
    }
}

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

namespace ProgrammingSystem
{
    public class Compiler
    {
        public Program Compile(Code code)
        {
            string template = @"
using System;
public class C 
{
    public event Output output;
    public void Run() 
    { 
        [[Source]]
        output(""end"");
    }
}
public delegate void Output(string s);
";

            string source = template.Replace("[[Source]]", code.Source);

            CodeDomProvider compiler = new CSharpCodeProvider();

            CompilerParameters parameters = new CompilerParameters();
            parameters.WarningLevel = 4;
            parameters.GenerateExecutable = false;
            parameters.GenerateInMemory = true;

            CompilerResults r = compiler.CompileAssemblyFromSource(parameters, source);
            foreach (var item in r.Output)
                this.Fire(Output, item);            

            Assembly assembly = r.CompiledAssembly;

            return new Program(assembly);
        }

        public event EventHandler<OutputEventArgs> Output;
    }
}
person Aaron Anodide    schedule 28.09.2012