在多个成员上使用 Postsharp 方面,而无需对它们进行多重转换

本文关键字:转换 成员 方面 Postsharp | 更新日期: 2023-09-27 18:33:51

是否可以在不使用MulticastAttributeUsage的情况下将Postsharp属性应用于类,接口,属性,字段或方法,以便用户准确决定将其应用于哪些成员,而无需对每个成员进行多重转换。

如果我使用 MulticastAttributeUsage 并在类上使用我的属性,它会自动将我的属性的新实例放在生成的 IL 中的所有属性、方法等上。

如果我不使用它,它就不会编译,因为它抱怨我需要使用它(我是从 Aspect 类派生的(。

这是我的方案:

我正在创建一个新的序列化属性,所以我希望能够这样做:

[Serialise(ApplyToProperty="Test2", Name="Blah2")]
public class MyClass {
    [Serialise(Name="Blah1")]
    public string Test1 { get; set; }
    public bool Test2 { get; set; }
}

当我在运行时使用 MulticastAttributeUsage 进行反思时,我在 Test1 上得到了两个序列化属性。 当我查看生成的 IL 时,它显示以下内容:

[Serialise(ApplyToProperty = "Test2", Name = "Blah2")]
public class Test {
    [Serialise(ApplyToProperty = "Test2", Name = "Blah2"), Serialise(Name = "Blah")]
    public string Test1 { get; set; }
    [Serialise(ApplyToProperty = "Test2", Name = "Blah2")]
    public bool Test2 { get; set; }
}

我不能使用 Postsharp,运行时的反射将完全满足我的需求,但我需要使用 Postsharp 来引入另一个方面。 我的序列化属性代码是这样的:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Property | AttributeTargets.Field)]
[MulticastAttributeUsage(MulticastTargets.Class | MulticastTargets.Interface | MulticastTargets.Property | MulticastTargets.Field, AllowMultiple = true, PersistMetaData = true, Inheritance = MulticastInheritance.None)]
public class SerialiseAttribute : Aspect, IAspectProvider {
    public string ApplyToProperty { get; set; }
    public string Name { get; set; }
    public override bool CompileTimeValidate(object target) {           
        return false;
    }       
    IEnumerable<AspectInstance> IAspectProvider.ProvideAspects(object targetElement) {
        // Code that introduces a different attribute
    }
}

另请注意,我从 CompileTimeValidate 返回 false 的事实似乎对生成的 IL 没有任何影响,不幸的是,"静默失败"并不意味着"不要将属性应用于它"。 那么,如何防止 Postsharp 实际上将属性多播到所有成员呢?

在多个成员上使用 Postsharp 方面,而无需对它们进行多重转换

您的自定义属性派生自Aspect类,而该类又派生自MulticastAttribute - 这就是您获得多播行为的原因。

相反,您可以做的是从System.Attribute派生并实现所需的所有接口。在你的情况下,这将是IAspectProviderIValidableAnnotation

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Property | AttributeTargets.Field)]
public class Serialise : Attribute, IAspectProvider, IValidableAnnotation
{
    public string ApplyToProperty { get; set; }
    public string Name { get; set; }
    public bool CompileTimeValidate(object target)
    {
        return false;
    }
    public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
    {
        // Code that introduces a different attribute
    }
}

至于CompileTimeValidate方法 - 此方法仅在执行多播以确定是否为每个已应用属性的给定代码元素引入方面后才会运行。