为什么不能在最新版本的PostSharp中将IInstanceScopedAspect应用于静态类?

问题描述 投票:0回答:1

我有这样的方面:

[PSerializable]
[AttributeUsage( AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property | AttributeTargets.Event, AllowMultiple = false )]
public abstract class LogAttribute : OnMethodBoundaryAspect, IInstanceScopedAspect {

    // CompileTime/Init
    public override void CompileTimeInitialize(MethodBase method, AspectInfo aspectInfo) {
    }
    // CompileTime/Validate
    public override bool CompileTimeValidate(MethodBase method) {
        return true;
    }

    // Runtime/Init/Static
    public override void RuntimeInitialize(MethodBase method) {
    }
    // Runtime/Init/Instance (Only if method is not static)
    object IInstanceScopedAspect.CreateInstance(AdviceArgs args) {
        var clone = (LogAttribute) MemberwiseClone();
        return clone;
    }
    void IInstanceScopedAspect.RuntimeInitializeInstance() {
    }


    // Advices
    public override void OnEntry(MethodExecutionArgs args) {
    }
    public override void OnSuccess(MethodExecutionArgs args) {
    }
    public override void OnException(MethodExecutionArgs args) {
    }
    public override void OnExit(MethodExecutionArgs args) {
    }
    public override void OnYield(MethodExecutionArgs args) {
    }
    public override void OnResume(MethodExecutionArgs args) {
    }

}

我将其用于非静态和静态方法和类。但是现在我不能在静态类中使用IInstanceScopedAspect

我遇到错误:Error LA0203 Cannot apply instance-level aspect "LogAttribute" to static class "...".

发生了什么变化?我现在该怎么办?

postsharp
1个回答
0
投票

这在PostSharp 6.4中是不允许的,因为有可能以违反C#对静态类(添加的实例成员等)的定义的方式更改方面的目标类。现在正确的方法是,如果需要使用IInstanceScopedAspect,则必须在实例方法和静态方法两个方面具有不同之处。

实现此目标的最佳方法是使IAspectProvider创建正确的外观:

[PSerializable]
public class LogAttribute : MethodLevelAspect, IAspectProvider
{
    public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
    {
        if (targetElement is MethodBase method)
        {
            if (method.IsStatic)
                yield return new AspectInstance(targetElement, new StaticLogAspect());
            else
                yield return new AspectInstance(targetElement, new InstanceLogAspect());
        }
    }
}

[PSerializable]
internal abstract class BaseLogAspect : IAspect
{
    [OnMethodEntryAdvice]
    [SelfPointcut]
    public virtual void OnEntry(MethodExecutionArgs args)
    {
        Console.WriteLine("Base");
    }
}

[PSerializable]
internal class StaticLogAspect : BaseLogAspect
{
    public override void OnEntry(MethodExecutionArgs args)
    {
        Console.WriteLine("Static");
    }
}

[PSerializable]
internal class InstanceLogAspect : BaseLogAspect, IInstanceScopedAspect
{
    public object CreateInstance(AdviceArgs adviceArgs)
    {
        return new InstanceLogAspect();
    }

    public void RuntimeInitializeInstance()
    {
    }

    public override void OnEntry(MethodExecutionArgs args)
    {
        Console.WriteLine("Instance");
    }
}

注意IInstanceScopedAspect导致为目标类的每个实例分配一个方面的对象。当您在方法上使用此方法时,此类方面可能会导致对象的内存占用量显着增加。

如果您的建议方法中需要与实例相关的信息,则最好在类型上使用一个“中心”实例作用域。该方面存储实例信息,并将接口引入目标类。然后,方法级方面将使用引入的接口来获取有关实例的信息。

© www.soinside.com 2019 - 2024. All rights reserved.