Можно ли вставить код IL в метод С#?
Как вставить CIL-код в C#
Ответы (5)
Я только что выложил утилиту, которая позволяет автоматически заменять целые тела функций C#. со встроенным IL, используя настраиваемый атрибут. Как и аналогичные утилиты, это работает через цикл ILDASM/ILASM, который можно настроить как шаг после сборки. Инструмент также настраивает PDB, чтобы сохранить пошаговое выполнение и установку точек останова для отдельных инструкций IL в отладчике. Он отличается от некоторых других встроенных IL-инлайнеров в оба конца тем, что он (только) заменяет целые тела функций, например:
class MyClass
{
[ILFunc(@"
.locals init ([0] int32 i_arg)
ldc.i4.3
ret
")]
int MyFunc(int i_arg)
{
return 3;
}
};
Для высококритичных к производительности методов я попытался использовать DynamicMethod
для улучшения генерируемого компилятором IL, но обнаружил, что преимущество теряется из-за накладных расходов, связанных с вызовом делегата. Встроенный IL дает преимущество ручной настройки IL без этого удара, при условии, что нет настроек времени выполнения, для которых вам действительно понадобится DynamicMethod
.
Полный исходный код находится по адресу http://www.glennslayden.com/code/c-sharp/inline-il
Attribute
.
- person Glenn Slayden; 02.02.2017
Если вам нужен встроенный IL (в духе встроенного ассемблера, поддерживаемого компиляторами C и C++), этого можно добиться с помощью циклической компиляции после компиляции.
Майк Столл однажды написал инструмент для этого, насколько я знаю, он довольно зрелый:
Кроме этого, вы можете использовать F#, который поддерживает Inline IL.
DynamicMethod — это упрощенный способ выполнить это. во время выполнения.
Компилятор Microsoft C# не поддерживает внедрение IL во время компиляции, но инструмент объединения кода может сделать это на этапе после компиляции.
Я добавлю свой собственный инструмент в список уже представленных здесь решений: InlineIL.Fody.
При этом используется инструмент создания сборки Fody для изменения сборки во время сборки. Это означает, что все, что вам нужно сделать, это установить пакет NuGet, добавить файл конфигурации в свой проект, и все готово.
Затем вам предоставляется простой и типобезопасный API для генерации инструкций IL, которые вы можете смешивать с кодом C#. Я считаю, что таким способом писать IL проще, чем писать текст, и это также удобнее, чем ILGenerator
, поскольку каждый опкод получает свой собственный метод только с соответствующими перегрузками.
Вот пример с using static InlineIL.IL.Emit;
:
public static void ZeroInit<T>(ref T value)
where T : struct
{
Ldarg(nameof(value));
Ldc_I4_0();
Sizeof(typeof(T));
Unaligned(1);
Initblk();
}
Здесь показано, как получить доступ к initblk
инструкция, которую C# в настоящее время не предоставляет.
Инструмент, который вам нужен, называется Cecil и является частью проекта Mono.
Вы можете получить больше информации об этом здесь: http://www.mono-project.com/Cecil а>
Цитата с сайта выше:
Cecil — это библиотека, написанная Jb Evain (http://evain.net/blog/) для создания и проверять программы и библиотеки в формате ECMA CIL. Он имеет полную поддержку дженериков и поддерживает некоторые форматы символов отладки.
Говоря простым английским языком, с помощью Cecil вы можете загружать существующие управляемые сборки, просматривать все содержащиеся в них типы, модифицировать их на лету и сохранять измененную сборку обратно на диск.