Как я могу превратить такие строки:
"call System.Console.WriteLine"
"ldstr \"hello\""
в инструкции с операндами?
Как я могу превратить такие строки:
"call System.Console.WriteLine"
"ldstr \"hello\""
в инструкции с операндами?
Если вы теперь знаете, как использовать Mono.Cecil
(или Reflection.Emit
), вопрос в более общем плане касается синтаксического анализа текста для кодирования действий.
У вас есть несколько способов сделать это, и я могу просто показать вам подсказку, и вы можете выбрать свой путь.
Прежде всего, вам потребуются некоторые предварительные условия (если ваш IL-текст является действительным кодом IL, эти предварительные условия уже существуют для вас). Например, вы не можете угадать, что такое Console.WriteLine
. Console
- это сборка, тип, метод? те же вопросы на WriteLine
. И даже если мы знаем, что WriteLine
— это метод, какую перегрузку нам нужно выбрать? а как же дженерики? Поэтому вам нужно установить контракт, который определяет, например, что точка является разделителем, а первый раздел — сборкой, второй — пространством имен и так далее.
Например:
"mscorlib.System.Console.WriteLine(string)"
будет переведено на System.Console.WriteLine(string)
После того, как у вас есть строгий контракт, вам нужно выполнить несколько шагов (для примера WriteLine
):
Assembly
и получите ModuleDefinition
Type
MethodReference
описание запрошенного методаОдин из способов сделать это — сохранить структуру кодов операций и необходимых для них действий.
Например, мы знаем, что инструкция call
нужна для вызова статического метода (в большинстве случаев), поэтому вам нужно отправить операнд в ParseStaticCall
, там вам нужно разобрать строку и выдать инструкцию вызова
Псевдокод:
new Dictionary<string, Tuple<OpCode, Action<string>>>
{
{
"call",
Tuple.Create<OpCode, Action<string>>
(OpCodes.Call,ParseStaticCall)
}
};
static void ParseStaticCall(Opcpde opcode,
string call,
ILProcessor processor)
{
string assembly, namespaceName, type, method;
int numOfParameters;
var moduleDefenition = AssemblyResolver.Resolve(assembly).MainModule;
var methodReference =
new ReferenceFinder(moduleDefenition).
GetMethodReference(typeof (Console),
md => md.Name == methodName &&
md.Parameters.Count == numOfParameters);
processor.Emit(opcode, methodReference);
}
AssemblyResolver
— это вспомогательный класс для поиска сборки по имени и пути (может быть постоянным путем). ReferenceFinder
— это вспомогательный класс, который находит тип\метод в конкретном модуле.
Таким образом, вам нужно создать метод и ILProccesor
для тела метода, затем для каждой строки, которая у вас есть, вам нужно отделить код операции инструкции от операнда, затем найти в словаре требуемое действие и передать код операции, операнд как строку и ILProccesor
.
Console.WriteLine
имеет много перегрузок, поэтомуcall System.Console.WriteLine
неоднозначен. Откуда у тебя эта строка? Что вы на самом деле пытаетесь сделать? - person svick   schedule 30.10.2016