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

Why can I not apply IInstanceScopedAspect to static class in last version of PostSharp?

我有这样一个方面:

[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 6.4 中是不允许的,因为可以以违反 C# 的静态 classes 定义(添加的实例成员等)的方式更改方面的目标 class。如果你需要 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 导致为每个目标实例分配一个方面对象 class。当您在方法上使用它时,此类方面可能会导致对象的内存占用量显着增加。

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