2013-02-03 29 views
5

Làm thế nào tôi có thể phản ánh được thuộc tính có DataMember với một tên đã cho (giả sử mỗi DataMember có một tên duy nhất)? Ví dụ, trong đoạn mã sau tài sản với DataMember có tên "p1" là PropertyOne:Cách nhận thuộc tính có thuộc tính DataMemberAttribute với tên được chỉ định?

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

Hiện nay, tôi có:

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

này hoạt động, nhưng nó cảm thấy như nó có thể là được cải thiện. Tôi đặc biệt không thích rằng GetCustomAttributes() được gọi là hai lần.

Làm cách nào để được viết lại tốt hơn? Lý tưởng nhất, nó sẽ là tuyệt vời nếu tôi có thể làm cho nó một lớp lót đơn giản.

+0

Nó sẽ hiệu quả hơn để đầu lọc ra các thành viên mà không có một 'DataMemberAttribute' ở tất cả, và chỉ tải các dữ liệu thuộc tính cho những người có nó. Sử dụng phương thức tĩnh ['Attribute.IsDefined'] (http://msdn.microsoft.com/en-us/library/2fdf7hf1.aspx" trang tham chiếu MSDN ") cho mục đích này ... Nó hiệu quả hơn' GetCustomAttribute' . – stakx

Trả lời

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

Ghi chú:

  • Attribute.IsDefined được sử dụng để kiểm tra sự hiện diện của một thuộc tính tùy chỉnh mà không cần lấy dữ liệu của nó. Do đó, nó hiệu quả hơn Attribute.GetCustomAttribute và được sử dụng để bỏ qua các thuộc tính trong bước đầu tiên.

  • Sau khi các nhà điều hành Where, chúng tôi là trái với các tính chất có chính xác mộtDataMemberAttribute: Thuộc tính mà không thuộc tính này đã được lọc ra, và nó không thể được áp dụng nhiều hơn một lần. Do đó, chúng tôi có thể sử dụng Attribute.GetCustomAttribute thay vì Attribute.GetCustomAttributes.

2

Bạn có thể sử dụng 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(); 

hoặc nếu bạn thích:

string dataMemberName = ...; 
var propInfo = typeof(T) 
    .GetProperties() 
    .Where(p => p 
     .GetCustomAttributes(typeof(DataMemberAttribute), false) 
     .OfType<DataMemberAttribute>() 
     .Any(x => x.Name == dataMemberName) 
    ) 
    .FirstOrDefault(); 
1

Bạn có thể sử dụng Fasterflect để làm cho mã phản ánh của bạn đơn giản và dễ dàng hơn trên mắt:

var property = typeof(T).MembersAndAttributes(MemberTypes.Property, typeof(DataMemberAttribute)) 
    .Where(ma => ma.Attributes.First().Name == dataMemberName) 
    .Select(ma => ma.Member as PropertyInfo) 
    .FirstOrDefault(); 

Nếu bạn chỉ cần kiểm tra sự hiện diện của thuộc tính, một cái gì đó như thế này có thể được sử dụng để thay thế:

var property = typeof(T).PropertiesWith<DataMemberAttribute>(Flags.InstancePublic) 
    .Where(p => p.Name == dataMemberName).FirstOrDefault(); 

Nhanh hơn với một bộ phương pháp tiện ích mở rộng và bao gồm một số tối ưu hóa hiệu suất gọn gàng khi sử dụng thế hệ IL nếu bạn cũng cần tốc độ.

1

tôi cần để có được giá trị của tài sản và không phải là tài sản riêng của mình quá quen Darin Dimitrov's answer nhưng nói thêm .GetValue(this) đến cùng để trả về giá trị thay thế.

Đây là những gì lớp học của tôi đã kết thúc tìm kiếm như:

[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); 
    } 
} 
Các vấn đề liên quan