pamidur / aspect-injector

AOP framework for .NET (c#, vb, etc)
Apache License 2.0
742 stars 111 forks source link

[Question] Is there a way to dynamically add aspects, as well as how to make Inherited on attributes work? #187

Closed NewMySQL closed 2 years ago

NewMySQL commented 2 years ago

1) Why inherited on attributes doesn't work? Code:

public class TestBase : Base
{
    public override void Hello()
    {
        Console.WriteLine("Hello, Git Hub!");
    }
}

public class Base
{
    [Log]
    public virtual void Hello()
    {

        Console.WriteLine("Hello, World!");
    }
}

[Aspect(Scope.Global)]
[Injection(typeof(Log))]
[AttributeUsage(AttributeTargets.Method, Inherited = true)]
public class Log : Attribute
{
    [Advice(Kind.Before, Targets = Target.Method)]
    public void OnEntry([Argument(Source.Name)] string name)
    {
        Console.WriteLine($"Entering method {name}");
    }
}

Wait after new TestBase().Hello():

Entering method Hello
Hello, Git Hub!

Result after new TestBase().Hello():

Hello, Git Hub!

2) How can I force an aspect to be added to certain methods at runtime?

class TestBase : Base
{
    public IResult Method1() { ... }
}
class Base
{
    public Base()
    {
        var currentType = this.GetType();
        var methods = currentType.GetMethods()
            .Where(c => typeof(IResult).IsAssignableFrom(c.ReturnType));

        foreach (var method in methods)
        {
            // How to make it possible?
            method.AddAspect(...)
        }
    }
}

interface IResult { ... }
pamidur commented 2 years ago

Hello @NewMySQL ,

So lets start with question # 2 - AspectInjector is compile time framework. So unfortunately you cannot add any aspects at runtime. At least for now.

For the # 1 - unfortunately the same - overridden virtual methods do not inherit aspects. This feature though can be (samewhat) easily implemented.

As a temporal solution you can use Interface triggers, something like:

[Injection(typeof(Log))]
public interface IInheritAspects{
}

public class TestBase : Base
{
    public override void Hello()
    {
        Console.WriteLine("Hello, Git Hub!");
    }
}

public class Base : IInheritAspects
{
    public virtual void Hello()
    {
        Console.WriteLine("Hello, World!");
    }
}

the side effect is that then [Log] will be injected into all and every methods of Base and TestBase. So you might need additional code to decide which method to log

NewMySQL commented 2 years ago

Hello @NewMySQL ,

So lets start with question # 2 - AspectInjector is compile time framework. So unfortunately you cannot add any aspects at runtime. At least for now.

For the # 1 - unfortunately the same - overridden virtual methods do not inherit aspects. This feature though can be (samewhat) easily implemented.

As a temporal solution you can use Interface triggers, something like:

[Injection(typeof(Log))]
public interface IInheritAspects{
}

public class TestBase : Base
{
    public override void Hello()
    {
        Console.WriteLine("Hello, Git Hub!");
    }
}

public class Base : IInheritAspects
{
    public virtual void Hello()
    {
        Console.WriteLine("Hello, World!");
    }
}

the side effect is that then [Log] will be injected into all and every methods of Base and TestBase. So you might need additional code to decide which method to log

Many thanks for the answer. Temporary solution, it suits me more than ever)