如何获取具有指定名称的DataMemberAttribute的属性?

如何reflection性地获取具有给定名称的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()被调用两次。

如何更好地重写? 理想情况下,如果我能把它变成一个简单的单行程,那将是很棒的。

 // 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

您可以使用LINQ:

 string dataMemberName = ...; var propInfo = (from property in typeof(T).GetProperties() let attributes = property .GetCustomAttributes(typeof(DataMemberAttribute), false) .OfType() 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() .Any(x => x.Name == dataMemberName) ) .FirstOrDefault(); 

您可以使用Fasterflect使您的reflection代码更简单,更容易:

 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( Flags.InstancePublic ) .Where( p => p.Name == dataMemberName ).FirstOrDefault(); 

Fasterflect附带了一组很好的扩展方法,如果你还需要速度,还可以使用IL生成一些整洁的性能优化。

我需要获取属性的值而不是属性本身所以使用Darin Dimitrov的答案但是添加.GetValue(this)到最后返回值。

这是我的class级最终看起来像:

 [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() .Any(x => x.Name == name))).GetValue(this); } }