Как я могу заменить реализацию метода во время выполнения?
-
28-09-2019 - |
Вопрос
Я хотел бы получить имущества и методы, которые я могу украсить с моим собственным пользовательским атрибутом и основываясь на наличии этого атрибута, замените тел метода с другим реализацией. Кроме того, эта другая реализация должна будет знать аргументы конструктора, приведенные пользовательскому атрибуту, где он украшает метод.
Это может быть, очевидно, можно сделать с помощью AOP, например, PostSharp или Linfu, но мне интересно, есть ли способ сделать это, что не связано с шагом обработки после сборки, потому что добавление, которое усложняет проект больше, чем я бы предпочел.
Решение
Использование традиционных API .NET нет возможности достичь этого. Тела метода фиксируются при компиляционном времени и не могут быть изменены.
Я говорю традиционные, хотя, потому что с Profiler и API-адресами INT технически можно изменить метод тел. Но эти API работают в ограниченных обстоятельствах и не считаются API общего назначения.
Другие советы
Можно с любыми хорошими рамками AOP, работающей во время выполнения. В настоящее время я работаю над одним из них с этой емкостью.
Вы можете найти это здесь : Nconcern .NET Runtime Aspect-ориентированное программирование
Немного примера, чтобы показать вам, как это работает ...
Предполагаемый пользовательский атрибут:
[AttributeUsage(AttributeTargets.Method, AllowMultiple=false, Inherited=true)]
public class MyAttribute1 : Attribute
{
public string MyAttributeValue;
}
Пример отмеченного CLASSE:
public class Calculator
{
[MyAttribute1(MyAttributeValue="Hello World")]
public int Add(int a, int b)
{
return a + b;
}
}
public class MyAspect : IAspect
{
//This code will be executed to create a decorator, not in nominal execution flow (You don't have to stress with performance here)
public IEnumerable<IAdvice> Advise(MethodInfo method)
{
var myattribute1 = method.GetCustomAttributes(typeof(MyAttribute1), true).Cast<MyAttribute1>().SingleOrDefault();
//If attribute is not defined, do not return an "advice"
if (myattribute1 == null) { yield break; }
//Get your attribute property.
var myattributevalue = myattribute1.MyAttributeValue;
//define your substitute method
var signature= new Type[] { method.DeclaringType }.Concat(method.GetParameters().Select(parameter => parameter.Type)).ToArray();
var dynamicMethod = new DynamicMethod(string.Empty, method.ReturnType, signature, method.DeclaringType, true);
var body = dynamicMethod.GetILGenerator();
//TODO : emit your code! maybe use your attribute field value to know what kind of replacement you want to do...
body.Emit(OpCodes.Ret);
//define the replacement
yield return new Advice(dynamicMethod);
}
}
Используйте корпус:
static public void main(string[] args)
{
Aspect.Weave<MyAspect>(method => method.IsDefined(typeof(MyAttribute1), true));
}
Существует пару рамки, которые позволяют динамически изменять любой метод во время выполнения:
- Пригород: Свободный и открытый источник!
- Гармония Открытый исходный код и MIT лицензирован, но .NET Поддержка кажется неполной в данный момент.
- Microsoft Fakes: Коммерческий, включенный в Visual Studio Premium и Ultimate, но не сообщество и профессионал
- Telerik Stackmock: Коммерческая версия "Lite" доступна
- Typemock isolator.: Реклама
Есть некоторые возможности, в зависимости от ваших точных потребностей. С момента .Net 1.0, можно перехватить вызовы, используя типы в System.runtime.remoting.proxies.proxies пространство имен.