Как изменить. Net Сборка во время выполнения и сохранить эти изменения - PullRequest
0 голосов
/ 24 марта 2020

Здравствуйте,

Я просто спрашиваю, есть ли способ в C#. Net изменить сборку во время выполнения, что я имею в виду, если у меня есть этот класс

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

Теперь мне нужно во время выполнения изменить Rest на 2, но сохранить эти изменения.

Итак, при следующем открытии программы я найду Rest=2.

Я знаю, я могу использовать файл конфигурации, БД, ... но я просто спрашиваю об этой возможности

Справочная информация

Я знаю о замене реализации методов во время выполнения, а также об Invoking / компилирование строкового кода с Roslyn во время выполнения

1 Ответ

0 голосов
/ 24 марта 2020

Интересно. Однако я не могу вспомнить ни одного варианта использования.

Я использовал Mono.Cecil ранее в цели MSBuild для изменения сборок на лету и сохранения обратно на диск.

Вот пример того, как вы могли бы сделать то, что вы просили:

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, использование / загрузка обновленной сборки будет проблемой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...