2013-02-03 81 views
5

我该如何反思性地获取具有给定名称的DataMember的属性(让我们假设每个DataMember都有一个唯一的名称)?例如,下面的代码使用具有名称“P1”的数据成员的属性是PropertyOne如何获取具有指定名称的DataMemberAttribute的属性?

[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

这将是更有效的先过滤掉没有'DataMemberAttribute'可言的,只加载属性数据的那些成员有它。为此,使用['Attribute.IsDefined'静态方法](http://msdn.microsoft.com/en-us/library/2fdf7hf1.aspx“MSDN参考页面”)...它比'GetCustomAttribute'更有效率。 – stakx

回答

9
// 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(); 
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代,如果你还需要一些速度整齐的性能优化。

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); 
    } 
}