如何获取具有指定名称的 DataMemberAttribute 的属性?
Posted
技术标签:
【中文标题】如何获取具有指定名称的 DataMemberAttribute 的属性?【英文标题】:How to get the property that has a DataMemberAttribute with a specified name? 【发布时间】:2013-01-18 06:04:54 【问题描述】:我怎样才能反射性地获取具有给定名称的 DataMember 的属性(假设每个 DataMember 都有一个唯一的名称)?例如,在以下代码中,名称为“p1”的 DataMember 的属性为 PropertyOne
:
[DataContract(Name = "MyContract")]
public class MyContract
[DataMember(Name = "p1")]
public string PropertyOne get; set;
[DataMember(Name = "p2")]
public string PropertyTwo get; set;
[DataMember(Name = "p3")]
public string PropertyThree get; set;
目前,我有:
string dataMemberName = ...;
var dataMemberProperties = typeof(T).GetProperties().Where(p => p.GetCustomAttributes(typeof(DataMemberAttribute), false).Any());
var propInfo = dataMemberProperties.Where(p => ((DataMemberAttribute)p.GetCustomAttributes(typeof(DataMemberAttribute), false).First()).Name == dataMemberName).FirstOrDefault();
这可行,但感觉可以改进。我特别不喜欢 GetCustomAttributes()
被调用两次。
如何更好地重写它?理想情况下,如果我能把它做成一个简单的单行线就好了。
【问题讨论】:
首先过滤掉根本没有DataMemberAttribute
的成员,只为有DataMemberAttribute
的成员加载属性数据会更有效。为此目的使用Attribute.IsDefined
static method...它比GetCustomAttribute
更有效。
【参考方案1】:
// using System.Linq;
// using System.Reflection;
// using System.Runtime.Serialization;
obj.GetType()
.GetProperties(…)
.Where(p => Attribute.IsDefined(p, typeof(DataMemberAttribute)))
.Single(p => ((DataMemberAttribute)Attribute.GetCustomAttribute(
p, typeof(DataMemberAttribute))).Name == "Foo");
注意事项:
Attribute.IsDefined
用于在不检索其数据的情况下检查自定义属性是否存在。因此它比Attribute.GetCustomAttribute
更有效,并且用于在第一步中跳过属性。
在Where
运算符之后,我们剩下的属性正好是一个 DataMemberAttribute
: 没有这个属性的属性已经被过滤掉了,它不能被多次应用.因此我们可以使用Attribute.GetCustomAttribute
而不是Attribute.GetCustomAttributes
。
【讨论】:
【参考方案2】:你可以使用 LINQ:
string dataMemberName = ...;
var propInfo =
(from property in typeof(T).GetProperties()
let attributes = property
.GetCustomAttributes(typeof(DataMemberAttribute), false)
.OfType<DataMemberAttribute>()
where attributes.Any(a => a.Name == dataMemberName)
select property).FirstOrDefault();
或者如果您愿意:
string dataMemberName = ...;
var propInfo = typeof(T)
.GetProperties()
.Where(p => p
.GetCustomAttributes(typeof(DataMemberAttribute), false)
.OfType<DataMemberAttribute>()
.Any(x => x.Name == dataMemberName)
)
.FirstOrDefault();
【讨论】:
【参考方案3】:您可以使用Fasterflect 使您的反射代码更简单、更容易看:
var property = typeof(T).MembersAndAttributes( MemberTypes.Property, typeof(DataMemberAttribute) )
.Where( ma => ma.Attributes.First().Name == dataMemberName )
.Select( ma => ma.Member as PropertyInfo )
.FirstOrDefault();
如果您只需要检查属性是否存在,则可以使用类似的方法:
var property = typeof(T).PropertiesWith<DataMemberAttribute>( Flags.InstancePublic )
.Where( p => p.Name == dataMemberName ).FirstOrDefault();
Fasterflect 带有一组不错的扩展方法,如果您还需要速度,还可以使用 IL 生成进行一些简洁的性能优化。
【讨论】:
【参考方案4】:我需要获取属性的值而不是属性本身,因此使用了Darin Dimitrov's answer,但在末尾添加了.GetValue(this)
以返回值。
这是我的班级最终的样子:
[DataContract]
public class Item
[DataMember(Name = "kpiId")]
public string KPIId get; set;
[DataMember(Name = "value")]
public string Value get; set;
[DataMember(Name = "unit")]
public string Unit get; set;
[DataMember(Name = "status")]
public string Status get; set;
[DataMember(Name = "category")]
public string Category get; set;
[DataMember(Name = "description")]
public string Description get; set;
[DataMember(Name = "source")]
public string Source get; set;
[DataMember(Name = "messages")]
public SysMessage[] Messages get; set;
public object getDataMemberByName(string name)
return (typeof(Item).GetProperties().FirstOrDefault(p => p.GetCustomAttributes(typeof(DataMemberAttribute), false)
.OfType<DataMemberAttribute>()
.Any(x => x.Name == name))).GetValue(this);
【讨论】:
以上是关于如何获取具有指定名称的 DataMemberAttribute 的属性?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用值数组在 Highcharts 饼图图例中获取数据名称而不是“切片”?
如何使用spring data elasticsearch创建具有指定名称的映射索引?