gpt4 book ai didi

.net - 使用 C# 动态编译代码

转载 作者:行者123 更新时间:2023-12-02 04:05:01 27 4
gpt4 key购买 nike

如何编写 C# 代码来编译和运行动态生成的 C# 代码。有没有例子?

我所追求的是动态构建一个(或多个)C# 类并在运行时运行它们。我希望生成的类能够与其他非动态的 C# 类交互。

我见过生成 exe 或 dll 文件的示例。我不在那之后,我只是希望它在内存中编译一些 C# 代码,然后运行它。例如,

所以这是一个不是动态的类,它将在我的 C# 程序集中定义,并且只会在编译时更改,

public class NotDynamicClass
{
private readonly List<string> values = new List<string>();

public void AddValue(string value)
{
values.Add(value);
}

public void ProcessValues()
{
// do some other stuff with values
}
}

这是我的动态类。我的 C# 代码将生成此类并运行它,

public class DynamicClass
{
public static void Main()
{
NotDynamicClass class = new NotDynamicClass();

class.AddValue("One");
class.AddValue("two");
}
}

所以结果是,最后我的非动态代码将调用 ProcessValues 并且它会执行一些其他操作。动态代码的目的是允许我们或客户向软件添加自定义逻辑。

谢谢。

最佳答案

两种可能性:

  1. Reflection.Emit
  2. System.CodeDom.Compiler
<小时/>

更新:

根据评论部分的要求,这里有一个完整的示例,说明了如何使用 Reflection.Emit 动态构建类并向其添加静态方法:

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;

public class NotDynamicClass
{
private readonly List<string> values = new List<string>();

public void AddValue(string value)
{
values.Add(value);
}

public void ProcessValues()
{
foreach (var item in values)
{
Console.WriteLine(item);
}
}
}

class Program
{
public static void Main()
{
var assemblyName = new AssemblyName("DynamicAssemblyDemo");
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, false);
var typeBuilder = moduleBuilder.DefineType("DynamicClass", TypeAttributes.Public);

var methodBuilder = typeBuilder.DefineMethod(
"Main",
MethodAttributes.Public | MethodAttributes.Static,
null,
new Type[0]
);

var il = methodBuilder.GetILGenerator();
var ctor = typeof(NotDynamicClass).GetConstructor(new Type[0]);
var addValueMi = typeof(NotDynamicClass).GetMethod("AddValue");
il.Emit(OpCodes.Newobj, ctor);
il.Emit(OpCodes.Stloc_0);
il.DeclareLocal(typeof(NotDynamicClass));
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldstr, "One");
il.Emit(OpCodes.Callvirt, addValueMi);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldstr, "Two");
il.Emit(OpCodes.Callvirt, addValueMi);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Callvirt, typeof(NotDynamicClass).GetMethod("ProcessValues"));
il.Emit(OpCodes.Ret);
var t = typeBuilder.CreateType();
var mi = t.GetMethod("Main");
mi.Invoke(null, new object[0]);
}
}

您可以在非 NotDynamicClass 方法中放置断点,并查看它们是如何被调用的。

<小时/>

更新2:

下面是 CodeDom 编译器的示例:

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

public class NotDynamicClass
{
private readonly List<string> values = new List<string>();

public void AddValue(string value)
{
values.Add(value);
}

public void ProcessValues()
{
foreach (var item in values)
{
Console.WriteLine(item);
}
}
}

class Program
{
public static void Main()
{
var provider = CSharpCodeProvider.CreateProvider("c#");
var options = new CompilerParameters();
var assemblyContainingNotDynamicClass = Path.GetFileName(Assembly.GetExecutingAssembly().Location);
options.ReferencedAssemblies.Add(assemblyContainingNotDynamicClass);
var results = provider.CompileAssemblyFromSource(options, new[]
{
@"public class DynamicClass
{
public static void Main()
{
NotDynamicClass @class = new NotDynamicClass();
@class.AddValue(""One"");
@class.AddValue(""Two"");
@class.ProcessValues();
}
}"
});
if (results.Errors.Count > 0)
{
foreach (var error in results.Errors)
{
Console.WriteLine(error);
}
}
else
{
var t = results.CompiledAssembly.GetType("DynamicClass");
t.GetMethod("Main").Invoke(null, null);
}
}
}

关于.net - 使用 C# 动态编译代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4718329/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com