【问题标题】:How to get the property that has a DataMemberAttribute with a specified name?如何获取具有指定名称的 DataMemberAttribute 的属性?
【发布时间】: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 更有效。

标签: c# .net reflection properties propertyinfo


【解决方案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);
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2010-09-22
          • 1970-01-01
          • 1970-01-01
          • 2023-02-25
          • 2011-04-12
          • 1970-01-01
          • 1970-01-01
          • 2014-06-09
          • 2012-01-09
          相关资源
          最近更新 更多