Как внедрить атрибут с помощью атрибута PostSharp?

Как я могу написать аспект PostSharp для применения атрибута к классу? Рассматриваемый мной сценарий - это объект WCF (или объект домена), который необходимо украсить атрибутом DataContract . Он также должен иметь свойство Пространство имен . Примерно так:

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; }
        }
    }
}

В приведенном выше примере вы можете увидеть, как я хочу, чтобы результат выглядел. К классу применен атрибут DataContract. Делать это вручную утомительно и не уникально. Я действительно просто хотел бы написать единственный аспект, который можно было бы применить к моему пространству имен «Домен». Затем он применил бы для меня атрибуты, связанные с сериализацией. Таким образом, я могу просто сосредоточиться на разработке объектов сущностей и не беспокоиться о деталях сериализации.

Я нашел документацию на веб-сайте PostSharp по внедрению кода до, после и вместо методов. Однако я ищу способ ввести атрибут в тип.


Вот решение!

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
    {
    }
}
7
задан Paul Fryer 21 October 2011 в 20:10
поделиться