如何修改.运行时的Net Assembly并保留这些更改



你好,

我只是问C#中是否有方法。Net在运行时修改程序集,我的意思是如果我有这类

public static class TimesTracker
{
public static int Rest = 3;
}

现在,我需要在运行时将Rest更改为2,但保留这些更改。

所以,下次打开程序时,我会发现Rest=2

我知道,我可以使用配置文件,数据库。。。但我只是问的这种可能性

背景

我知道在运行时替换方法的实现,也知道在运行时使用Roslyn调用/编译字符串代码

有趣。然而,我想不出任何用例。

我以前在MSBuild目标中使用过Mono.Cecil来动态修改程序集并保存回磁盘。

下面是一个如何完成您要求的示例:

var filePath = "Assembly path";
var updatedFilePath = "Updated assembly path";
// Read assembly
using (var assembly = AssemblyDefinition.ReadAssembly(filePath))
{
// Find type TimesTracker. This example was done in LINQPad, so TimesTracker is nested type inside UserQuery
var type = assembly.MainModule.Types.SelectMany(t => t.NestedTypes).First(td => td.Name == "TimesTracker");
// Find static constructor
var cctor = type.Methods.First(md => md.Name == ".cctor");
// Get IL
var il = cctor.Body.GetILProcessor();
// The IL of Rest = 3 is:
// IL_0000: ldc.i4.3
// IL_0001: stsfld int32 UserQuery / TimesTracker::Rest
var op = il.Body.Instructions.First(i => i.OpCode == OpCodes.Ldc_I4_3);
// Replace 3 with 7
var newOp = il.Create(OpCodes.Ldc_I4_7);
il.Replace(op, newOp);
// Write updated to another assembly file
assembly.Write(updatedFilePath);
}
// Load updated assembly into AppDomain
var updatedAssembly = Assembly.LoadFile(updatedFilePath);
// Use reflection to get value of Rest
var updatedType = updatedAssembly.DefinedTypes.First(t => t.Name.Contains("TimesTracker"));
var field = updatedType.GetField("Rest", BindingFlags.Public | BindingFlags.Static);
// value is now 7
var value = (int)field.GetValue(null);

注意以上代码只能修改:

public class TimesTracker
{ 
public static int Rest = 3;
}

然而,因为C#不允许重新加载程序集,除非卸载整个AppDomain,所以使用/加载更新的程序集将是一个挑战。

最新更新