Как заменить реализацию метода во время выполнения?

Я хотел бы иметь свойства getters и методы, которые я могу украсить своим собственным настраиваемым атрибутом и на основе присутствия этого атрибута заменить тела метода другой реализацией. Кроме того, эта разная реализация должна знать аргументы конструктора, заданные для пользовательского атрибута, где он украшает этот метод.

Это, очевидно, можно сделать с помощью AOP, например PostSharp или LinFu, но мне интересно, есть ли способ сделать это, не связанный с этапом обработки после сборки, потому что добавление, которое усложняет проект, больше, чем я предпочел бы.

Ответ 1

Использование традиционных API-интерфейсов .Net невозможно. Органы метода фиксируются во время компиляции и не могут быть изменены.

Я говорю традиционно, хотя, поскольку с помощью профилировщика и API ENC технически можно изменить тела методов. Но эти API-интерфейсы работают в ограниченных условиях и не считаются API-интерфейсами общего назначения.

Ответ 2

Существует несколько фреймворков, которые позволяют динамически изменять любой метод во время выполнения:

  • Prig: бесплатный и открытый исходный код!
  • Harmony Лицензия на использование Open Source и MIT, но поддержка .net кажется неполной на данный момент.
  • Microsoft Fakes: Коммерческий, включенный в Visual Studio Premium и Ultimate, но не Community и Professional
  • Telerik JustMock: Коммерческая, доступна версия "lite"
  • Typemock Isolator: Коммерческий

Ответ 3

Это возможно с любой хорошей структурой AOP, работающей во время выполнения. В настоящее время я работаю над одним из них с этой способностью.

Вы можете найти его здесь: Нестандартное программирование NConcern.NET

Небольшой пример, чтобы показать вам, как он работает...

Предполагаемый пользовательский атрибут:

[AttributeUsage(AttributeTargets.Method, AllowMultiple=false, Inherited=true)]
public class MyAttribute1 : Attribute
{
    public string MyAttributeValue;
}

Пример отмеченного класса:

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));
}

Ответ 4

Есть несколько возможностей, в зависимости от ваших конкретных потребностей. С тех пор, как .NET 1.0, было возможно перехватить вызовы с использованием типов в пространстве имен System.Runtime.Remoting.Proxies.