【发布时间】:2011-10-21 15:03:33
【问题描述】:
如何编写 PostSharp 方面以将属性应用于类?我正在考虑的场景是需要使用DataContract 属性修饰的WCF 实体(或域对象)。它还应该有一个Namespace 属性。像这样:
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 的网站上找到了用于在之前、之后和而不是方法注入代码的文档。但是,我正在寻找一种将 Attribute 注入类型的方法。
这是解决方案!
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
{
}
}
【问题讨论】:
-
在这里找到解决方案:doc.sharpcrafters.com/postsharp-2.1/…
-
CopyCustomAttribute 不符合您的要求。它仅将自定义属性应用于您要引入目标类型的成员。它不会将属性应用于现有成员。
-
@DustinDavis 我已经删除了对 CopyCustomAttribute 的引用,所以我们不会混淆任何人。
-
必须用 PostSharp 完成吗?使用 Mono Cecil 很简单。