Код выполнения впрыска с использованием DynamicMethod?
-
08-10-2019 - |
Вопрос
Рассмотрим следующий тривиальный код:
using System;
class Test
{
delegate int FooDelegate(int i);
FooDelegate Foo = FooImplementation;
static int FooImplementation(int i)
{
return i + 1;
}
public static void Main()
{
Foo(1);
}
}
То, что я хотел бы сделать, это ввести какой-то код отладки в делегат Foo, который будет эквивалентен:
FooDelegate Foo = delegate(int i)
{
try
{
DebugPrologue();
return FooImplementation(i);
}
finally
{
DebugEpilogue();
}
};
Твист в том, что я должен быть в состоянии сделать это в время выполнения, поэтому методы комбинированного времени и последующие методы находятся в рецензии.
Мой первоначальный подход использовал Delage.comBine () для добавления методов пролога и эпилюга в делегат FOO. Увы, это не будет работать так, как он помогает возвращать значения.
Моя текущая идея состоит в том, чтобы использовать System.reflection.emit и DynamicMethod в качестве потенциального решения. Насколько я могу сказать, мне нужно получить методинфо для FOOOIMPLEMENTATION, получите свой метод, преобразуйте это на динамику и введите мою попытку, наконец-то блок в это.
К сожалению, я не имею абсолютно не знаю, как это сделать. Кто-нибудь готов давать руку? Или у вас есть еще одна (предпочтительно простая) идея?
Редактировать: использование-корпус здесь отладки привязки OpenGL (http://www.opentk.com). Мы должны вводить 2226 методов с дико разными параметрами, поэтому необходим общий подход.
Решение 6
То, что я, наконец, оказался, это реализовать свое собственное переписанное решение с использованием Mono.cecil. Просто, быстро и работает нормально. К сожалению, это должно быть сделано как событие после сборки, поэтому это на самом деле не впрыска кода выполнения.
Другие советы
Вы можете использовать выражения.
var param = Expression.Parameter(typeof(int), "i");
Foo = Expression.Lambda(
Expression.TryFinally(
Expression.Block(
<expression for DebugPrologue>,
Expression.Invoke(<expression for FooImplementation>, param)),
<expression for DebugEpilogue>),
param)
.Compile();
Таким образом, вы можете построить выражения для пролога и эпилога во время выполнения.
Обратите внимание, что вы пытаетесь сделать, но если это просто перенаправляет FooImplementation
это указано на Foo
Поле тогда вы можете просто сделать:
class Test
{
delegate int FooDelegate(int i);
static FooDelegate Foo = FooImplementation;
static int FooImplementation(int i)
{
return i + 1;
}
public static void Main()
{
Inject();
Foo(1);
}
public static void Inject()
{
var oldImpl = Foo;
Foo = i =>
{
try
{
BeginDebug();
return oldImpl(i);
}
finally
{
EndDebug();
}
};
}
public static void BeginDebug()
{
Console.WriteLine("Begin Foo");
}
public static void EndDebug()
{
Console.WriteLine("End Foo");
}
}
Конечно, ввод не должен быть в том же классе, однако, если поле / имущество не публично доступно, вам придется использовать отражение, чтобы сделать это, все еще не так сложно.
Вы считаете, что используете что-то вроде: postsharp?http://www.sharpcrafters.com/postsharp.
или предпринимательская политика библиотеки впрыскивается?http://msdn.microsoft.com/en-us/library/ff650672.aspx.
Или даже mono.cecil?http://www.mono-project.com/Cecil.
Typemock также может быть жизнеспособным решением вашей проблемы:http://www.typemock.com/
Вы также можете использовать RealProxy Class (http://msdn.microsoft.com/en-us/library/system.runtime.remoting.proxies.realProxy.aspx) для создания собственного прокси во время выполнения, которые сначала позвоните в дополнительный код а затем вызвать фактический метод.
Вы также можете попробовать Цилиндр На CodeePlex для ввода кода в управляемый код (C # или VB.NET) с большой легкостью.