如何将编译器检查的属性名称/表达式树传递给自定义属性
在一些地方,我注意到表达式树作为参数传递给方法,以允许编译器检查属性名称。 例如,Caliburn Micro在其PropertyChangedBase类中具有以下方法签名:
public virtual void NotifyOfPropertyChange(Expression<Func> property);
我有一个自定义属性,我想在构造函数中使用相同类型的编译器检查属性名称,以使我能够键入:
[MyCustomAttribute(() => PropertyName)]
代替:
[MyCustomAttribute("PropertyName")]
使用构造函数定义:
public MyCustomAttribute(params Expression<Func>[] properties)
但是,由于属性参数的限制是常量表达式,这似乎是不可能的。
任何人都可以推荐一种不同的方法,我可以让编译器检查我的属性参数中的属性名称,而不是留下这个只使用字符串的潜在错误?
编辑:感谢Marc的回答,我现在已经实现了这个:
#if DEBUG foreach (var propertyInfo in GetType().GetProperties().Where(propertyInfo => Attribute.IsDefined(propertyInfo, typeof (MyCustomAttribute)))) { foreach (var propertyName in propertyInfo.GetAttributes(true) .SelectMany(attribute => attribute.PropertyNames)) Debug.Assert( GetType().GetProperty(propertyName) != null, "Property not found", "Property {0} declared on attributed property {1} was not found on type {2}.", propertyName, propertyInfo.Name, GetType().Name ); } #endif
这根本不可能。 属性仅限于非常基本的类型,不包括您需要的内容。 一种可能的静态安全方法是将每个属性的属性子类化,但这是一项疯狂的工作量。
就个人而言,我只是编写一个unit testing,找到所有出现的属性并通过reflection检查它们是否合理。 您也可以在#if DEBUG
块(或类似)中的主代码中执行此操作。
使用PostSharp有几种解决方案(免责声明:我是男士),其中一些使用免费版。
解决方案1
您可以使用PostSharp方面并使用CompileTimeInitialize来读取属性名称。
例如:
[Serializable] class MyCustomAttribute : LocationLevelAspect { string propertyName; public override void CompileTimeInitialize( LocationInfo targetLocation, AspectInfo aspectInfo ) { this.propertyName = targetLocation.PropertyName; } }
此function存在于免费的PostSharp社区版中。
问题是使用System.Reflection看不到以这种方式构建的自定义属性。
解决方案2
您还可以使用添加自定义属性的方面。 然后,该方面应实现IAspectProvider并返回CustomAttributeIntroductionAspect的实例。 您可以从此页面获得灵感。 PostSharp专业版($)提供此function。
解决方案3
您还可以使自定义属性类(任何类,而不是特定方面)实现接口IValidableAnnotation:
public class MyAttribute : Attribute, IValidableAnnotation { private string propertyName; public MyAttribute(string propertyName) { this.propertyName = propertyName; } public bool CompileTimeValidate( object target ) { PropertyInfo targetProperty = (PropertyInfo) target; if ( targetProperty.Name != propertyName ) { Message.Write( Severity.Error, "MY001", "The custom attribute argument does not match the property name."); return false; } } }
这可以使用PostSharp的免费版本,您可以轻松地将其包含在#if /#endif块中,以使您的代码完全独立于PostSharp(如果您愿意)。
上述就是C#学习教程:如何将编译器检查的属性名称/表达式树传递给自定义属性分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/949420.html