如何反射性地获取具有给定名称的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()
被叫两次。
怎样才能更好地重写?理想情况下,如果我能把它变成一个简单的单行,那就太好了。
答案 0 :(得分:10)
// 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
。
答案 1 :(得分: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();
答案 2 :(得分:1)
您可以使用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生成一些整洁的性能优化。
答案 3 :(得分:1)
我需要获取属性的值而不是属性本身所以使用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);
}
}