如何注入使用PostSharp属性的属性? [英] How to inject an attribute using a PostSharp attribute?

查看:334
本文介绍了如何注入使用PostSharp属性的属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我怎么能写一个PostSharp方面的属性应用到一个类?我正在考虑的方案是需要与 DataContract 属性来装饰一个WCF实体(或域对象)。它也应该有一个命名空间属性。像这样的:

 使用System.Runtime.Serialization;

命名空间MWS.Contracts.Search.V1
{
    命名空间域名
    {
        [DataContract(命名空间= XmlNamespaces.SchemaNamespace)
        公共类PagingContext
        {
            [数据成员]
            公众诠释页{获得;组; }

            [数据成员]
            公众诠释ResultsPerPage {获得;组; }

            [数据成员]
            公众诠释MaxResults {获得;组; }
        }
    }
}
 

在上面的例子中,你可以看到我想要输出的样子。它适用于类DataContract属性。做手工,这是乏味的,而不是唯一的。我真的只是想编写一个可以应用了我的域名称空间中的一个方面。这将适用序列化相关的属性我。这样我可以专注于开发实体对象,而不用担心序列化pluming细节。

我发现在PostSharp网站上的文档前注射后的,而是方法code。但是我正在寻找一种方法来一个属性到一个类型的注入。


这是解决方案!

 使用系统;
使用System.Collections.Generic;
使用System.Linq的;
使用的System.Reflection;
使用System.Runtime.Serialization;
使用PostSharp.Aspects;
使用PostSharp.Extensibility;
使用PostSharp.Reflection;

命名空间MWS.Contracts.Aspects
{
    //我们建立了多播继承,以便方面会自动添加到孩子的类型。
    [MulticastAttributeUsage(MulticastTargets.Class,继承= MulticastInheritance.Strict)
    [可序列化]
    公共密封类AutoDataContractAttribute:TypeLevelAspect,IAspectProvider
    {
        私人只读字符串xmlNamespace;

        公共AutoDataContractAttribute(字符串xmlNamespace)
        {
            this.xmlNamespace = xmlNamespace;
        }

        //此方法被调用在构建时,应该只是提供其他方面。
        公开的IEnumerable< AspectInstance> ProvideAspects(对象targetElement)
        {
            VAR TARGETTYPE =(类型)targetElement;

            VAR introduceDataContractAspect =
                新CustomAttributeIntroductionAspect(
                    新ObjectConstruction(typeof运算(DataContractAttribute).GetConstructor(Type.EmptyTypes)));

            introduceDataContractAspect.CustomAttribute.NamedArguments.Add(命名空间,xmlNamespace);

            VAR introduceDataMemberAspect =
                新CustomAttributeIntroductionAspect(
                    新ObjectConstruction(typeof运算(DataMemberAttribute).GetConstructor(Type.EmptyTypes)));

            //该DataContract属性添加到类型。
            产量返回新AspectInstance(TARGETTYPE,introduceDataContractAspect);

            //添加一个数据成员属性,每一个相关的属性。)))
            中的foreach(VAR财产
                targetType.GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance)
                    。凡(属性=>
                           property.CanWrite&功放;&安培;
                           !property.IsDefined(typeof运算(NotDataMemberAttribute),FALSE)))
                收益回报新AspectInstance(财产,introduceDataMemberAspect);
        }
    }

    [AttributeUsage(AttributeTargets.Property)
    公共密封类NotDataMemberAttribute:属性
    {
    }
}
 

解决方案

请参阅<一href="http://www.sharpcrafters.com/blog/post/PostSharp-Principals-Day-12-e28093-Aspect-Providers-e28093-Part-1.aspx" rel="nofollow">http://www.sharpcrafters.com/blog/post/PostSharp-Principals-Day-12-e28093-Aspect-Providers-e28093-Part-1.aspx

下面是一个工作的例子。施加该方面的一类将应用XmlIgnore属性到没有已有的XmlElement或XmlAttribute施加到其上的任何公共属性。诀窍是使用内置于Postsharp的CustomAttributeIntroductioinAspect。你只需要实例化一个实例指定的属性类型和构造器的详细信息,然后创建一个提供者将其应用到目标(S)。

 使用系统;
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;
使用PostSharp.Extensibility;
使用PostSharp.Aspects;
使用PostSharp.Reflection;
使用的System.Xml.Serialization;

命名空间ApplyingAttributes
{
    [MulticastAttributeUsage(MulticastTargets.Field | MulticastTargets.Property,
                            TargetMemberAttributes = MulticastAttributes.Public | MulticastAttributes.Instance)]
    公共密封类AddXmlIgnoreAttribute:LocationLevelAspect,IAspectProvider
    {
        私人静态只读CustomAttributeIntroductionAspect customAttributeIntroductionAspect =
            新CustomAttributeIntroductionAspect(
                新ObjectConstruction(typeof运算(XmlIgnoreAttribute).GetConstructor(Type.EmptyTypes)));

        公开的IEnumerable&LT; AspectInstance&GT; ProvideAspects(对象targetElement)
        {
            LocationInfo的MemberInfo =(LocationInfo)targetElement;

            如果(memberInfo.PropertyInfo.IsDefined(typeof运算(XmlElementAttribute),FALSE)||
                memberInfo.PropertyInfo.IsDefined(typeof运算(XmlAttributeAttribute),FALSE))
                产生中断;

            收益回报新AspectInstance(memberInfo.PropertyInfo,customAttributeIntroductionAspect);
        }
    }

}
 

要使用属性,指定参数,我用

 公共类MyAspect:TypeLevelAspect,IAspectProvider
{
    公开的IEnumerable&LT; AspectInstance&GT; ProvideAspects(对象targetElement)
    {
        收益回报创建&LT; MethodInfo的&GT;(MI,值);

    }

    私人AspectInstance创建&LT; T&GT;(T目标,串了newName)
    {
        VAR X =新CustomAttributeIntroductionAspect(
            新ObjectConstruction(typeof运算(NewMethodName).GetConstructor(新类型[] {typeof运算(字符串)}),新的对象[] {}了newName)
            );

        返回新AspectInstance(目标,X);
    }
}
 

How can I write a PostSharp aspect to apply an attribute to a class? The scenario I'm considering is a WCF entity (or domain object) that needs to be decorated with the DataContract attribute. It should also have a Namespace property. Like this:

using System.Runtime.Serialization;

namespace MWS.Contracts.Search.V1
{
    namespace Domain
    {
        [DataContract(Namespace = XmlNamespaces.SchemaNamespace)]
        public class PagingContext
        {
            [DataMember]
            public int Page { get; set; }

            [DataMember]
            public int ResultsPerPage { get; set; }

            [DataMember]
            public int MaxResults { get; set; }
        }
    }
}

In the above example you can see what I want the output to look like. It has the DataContract attribute applied to the class. Doing this by hand is tedious and not unique. I'd really just like to write a single aspect that can be applied a my "Domain" namespace. It would then apply the serialization related attributes for me. This way I can just focus on developing entity objects, and not worry about the serialization pluming details.

I have found documentation on PostSharp's website for injecting code before, after, and instead of methods. However what I'm looking for is a way to inject an Attribute onto a type.


Here is the solution!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using PostSharp.Aspects;
using PostSharp.Extensibility;
using PostSharp.Reflection;

namespace MWS.Contracts.Aspects
{
    // We set up multicast inheritance so  the aspect is automatically added to children types.
    [MulticastAttributeUsage(MulticastTargets.Class, Inheritance = MulticastInheritance.Strict)]
    [Serializable]
    public sealed class AutoDataContractAttribute : TypeLevelAspect, IAspectProvider
    {
        private readonly string xmlNamespace;

        public AutoDataContractAttribute(string xmlNamespace)
        {
            this.xmlNamespace = xmlNamespace;
        }

        // This method is called at build time and should just provide other aspects.
        public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
        {
            var targetType = (Type) targetElement;

            var introduceDataContractAspect =
                new CustomAttributeIntroductionAspect(
                    new ObjectConstruction(typeof (DataContractAttribute).GetConstructor(Type.EmptyTypes)));

            introduceDataContractAspect.CustomAttribute.NamedArguments.Add("Namespace", xmlNamespace);

            var introduceDataMemberAspect =
                new CustomAttributeIntroductionAspect(
                    new ObjectConstruction(typeof (DataMemberAttribute).GetConstructor(Type.EmptyTypes)));

            // Add the DataContract attribute to the type.
            yield return new AspectInstance(targetType, introduceDataContractAspect);

            // Add a DataMember attribute to every relevant property.)))
            foreach (var property in
                targetType.GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance)
                    .Where(property =>
                           property.CanWrite &&
                           !property.IsDefined(typeof (NotDataMemberAttribute), false)))
                yield return new AspectInstance(property, introduceDataMemberAspect);
        }
    }

    [AttributeUsage(AttributeTargets.Property)]
    public sealed class NotDataMemberAttribute : Attribute
    {
    }
}

解决方案

See http://www.sharpcrafters.com/blog/post/PostSharp-Principals-Day-12-e28093-Aspect-Providers-e28093-Part-1.aspx

Here is a working example. Applying this aspect to a class will apply the XmlIgnore attribute to any public property that does not already have XmlElement or XmlAttribute applied to it. the trick is using the CustomAttributeIntroductioinAspect that is built in to Postsharp. You just need to instantiate an instance specifying the attribute type and contructor details, then create a provider to apply it to the target(s).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PostSharp.Extensibility;
using PostSharp.Aspects;
using PostSharp.Reflection;
using System.Xml.Serialization;

namespace ApplyingAttributes
{
    [MulticastAttributeUsage(MulticastTargets.Field | MulticastTargets.Property,
                            TargetMemberAttributes = MulticastAttributes.Public | MulticastAttributes.Instance)]
    public sealed class AddXmlIgnoreAttribute : LocationLevelAspect, IAspectProvider
    {
        private static readonly CustomAttributeIntroductionAspect customAttributeIntroductionAspect =
            new CustomAttributeIntroductionAspect(
                new ObjectConstruction(typeof(XmlIgnoreAttribute).GetConstructor(Type.EmptyTypes)));

        public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
        {
            LocationInfo memberInfo = (LocationInfo)targetElement;

            if (memberInfo.PropertyInfo.IsDefined(typeof(XmlElementAttribute), false) ||
                memberInfo.PropertyInfo.IsDefined(typeof(XmlAttributeAttribute), false))
                yield break;

            yield return new AspectInstance(memberInfo.PropertyInfo, customAttributeIntroductionAspect);
        }
    }

}

To use attributes, specifying parameters, I use

 public class MyAspect : TypeLevelAspect, IAspectProvider
{
    public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
    {
        yield return Create<MethodInfo>(mi, "Value");

    }

    private AspectInstance Create<T>(T target, string newName)
    {
        var x = new CustomAttributeIntroductionAspect(
            new ObjectConstruction(typeof(NewMethodName).GetConstructor(new Type[] { typeof(string) }), new object[] { newName })
            );

        return new AspectInstance(target, x);
    }
}

这篇关于如何注入使用PostSharp属性的属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆