在运行时编译C#类并从原始代码调用方法

8
我正在尝试在C#中运行时编译代码,然后从编译后的代码中调用在原始代码中定义的函数或初始化一个类。
目前我拥有的代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;

namespace CTFGame
{
    class Program
    {
        static void Main(string[] args)
        {
            string code = @"

using System;

namespace CTFGame
{
    public class MyPlayer
    {
        public static void Main ()
        {
            Console.WriteLine(""Hello world"");
        }
        /*public void DoTurn ()
        {
            Program.SayHello();
        }*/
    }
}

";
            CSharpCodeProvider provider = new CSharpCodeProvider();
            CompilerParameters parameters = new CompilerParameters();
            parameters.GenerateInMemory = true;

            CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
            if (results.Errors.HasErrors)
            {
                string errors = "";
                foreach (CompilerError error in results.Errors)
                {
                    errors += string.Format("Error #{0}: {1}\n", error.ErrorNumber, error.ErrorText);
                }
                Console.Write(errors);
            }
            else
            {
                Assembly assembly = results.CompiledAssembly;
                Type program = assembly.GetType("CTFGame.MyPlayer");
                MethodInfo main = program.GetMethod("Main");
                main.Invoke(null, null);
            }
        }

        public static void SayHello()
        {
            Console.WriteLine("I'm awesome ><");
        }
    }
}

现在,运行动态加载的 "Main" 方法是成功的,并打印出消息 "Hello world"。问题从这里开始:在原始代码中,我有一个名为 "SayHello" 的方法。我想从我的运行时加载的代码中调用此方法。
如果我取消注释 "DoTurn" 方法,则会在运行时显示编译器错误:
Error #CS0103: The name 'Program' does not exist in the current context

我的问题是 - 这是否可能,以及如何实现?将运行时加载的代码放在相同的命名空间中并没有帮助(这很有道理),那么正确的方法是什么?谢谢。

2
您需要添加对您程序集的引用。 - SLaks
1
考虑使用Roslyn。 - SLaks
也许在尝试动态编译代码之前,你应该考虑让它能够正常编译。 - David L
如果我错了,请有人纠正我,但是你正在尝试做的事似乎会导致循环依赖。你编译的程序集不知道当前正在执行的程序集,但你正在尝试从编译的代码中调用当前程序集上的方法。 - Jonesopolis
谢谢,@SLaks。你说得没错。我添加了对当前运行程序集的引用,现在它可以完美地工作了。我将把它发布为答案,以便其他人也能从中受益。 非常感谢! - Yotam Salmon
显示剩余2条评论
1个回答

9

添加对当前程序集的引用解决了问题:

CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
parameters.GenerateInMemory = true;                
//The next line is the addition to the original code
parameters.ReferencedAssemblies.Add(Assembly.GetEntryAssembly().Location);

更多内容请参考: 使用用户定义的函数在运行时编译C#代码


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接