2013-05-15 40 views
7

Tôi đã có ExpandoObject mà tôi đang gửi đến một phương thức thư viện bên ngoài có đối tượng. Từ những gì tôi đã nhìn thấy lib bên ngoài này sử dụng TypeDescriptor.GetProperties nội bộ và dường như gây ra một số vấn đề với ExpandoObject của tôi.Hiển thị các thuộc tính của ExpandoObject

Tôi có thể đi với một đối tượng ẩn danh thay vào đó và điều đó có vẻ hiệu quả nhưng thuận tiện hơn cho tôi khi sử dụng ExpandoObject.

Tôi có cần xây dựng DynamicObject của riêng mình và tự chăm sóc bản thân bằng cách triển khai ICustomTypeDescriptor hoặc tôi thiếu thứ gì đó ở đây.

Ý tưởng?


Cập nhật

Bên cạnh những câu trả lời bằng somedave dưới đây (theo các ý kiến), tôi đã thêm lớp

public class ExpandoObjectTypeDescriptionProvider : TypeDescriptionProvider 
{ 
    private static readonly TypeDescriptionProvider m_Default = TypeDescriptor.GetProvider(typeof(ExpandoObject)); 

    public ExpandoObjectTypeDescriptionProvider() 
     :base(m_Default) 
    { 
    } 

    public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) 
    { 
     var defaultDescriptor = base.GetTypeDescriptor(objectType, instance); 

     return instance == null ? defaultDescriptor : 
      new ExpandoObjectTypeDescriptor(instance); 
    } 
} 

này và đăng ký nó như thế này:

dynamic parameters = new ExpandoObject(); 
TypeDescriptor.AddProvider(new ExpandoObjectTypeDescriptionProvider(), parameters); 
+0

Bạn có danh sách tên thuộc tính khi kết thúc không? –

+0

không phải trước thời gian (biên dịch thời gian) ... do đó ExpandoObject –

Trả lời

9

Thực hiện ICustomTypeDescriptor thực sự không phải là tất cả những khó khăn. Dưới đây là một số mẫu mã tôi thích nghi từ một số công việc tôi đã làm với lưới tài sản WinForms (trong đó sử dụng TypeDescriptor và PropertyDescriptor). Bí quyết là cũng triển khai lớp PropertyDescriptor thích hợp mà bạn có thể trả lại từ ICustomTypeDescriptor.GetProperties(). Rất may ExpandoObject làm cho điều này khá đơn giản bằng cách thực hiện IDictionary<string, object> để truy xuất động các khóa và giá trị của nó. Hãy nhớ rằng điều này có thể hoặc có thể không hoạt động chính xác (tôi chưa thử nghiệm nó) và nó có thể sẽ không làm việc cho ExpandoObjects với nhiều thuộc tính lồng nhau.

public class ExpandoTypeDescriptor : ICustomTypeDescriptor 
{ 
    private readonly ExpandoObject _expando; 

    public ExpandoTypeDescriptor(ExpandoObject expando) 
    { 
     _expando = expando; 
    } 

    // Just use the default behavior from TypeDescriptor for most of these 
    // This might need some tweaking to work correctly for ExpandoObjects though... 

    public string GetComponentName() 
    { 
     return TypeDescriptor.GetComponentName(this, true); 
    } 

    public EventDescriptor GetDefaultEvent() 
    { 
     return TypeDescriptor.GetDefaultEvent(this, true); 
    } 

    public string GetClassName() 
    { 
     return TypeDescriptor.GetClassName(this, true); 
    } 

    public EventDescriptorCollection GetEvents(Attribute[] attributes) 
    { 
     return TypeDescriptor.GetEvents(this, attributes, true); 
    } 

    EventDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetEvents() 
    { 
     return TypeDescriptor.GetEvents(this, true); 
    } 

    public TypeConverter GetConverter() 
    { 
     return TypeDescriptor.GetConverter(this, true); 
    } 

    public object GetPropertyOwner(PropertyDescriptor pd) 
    { 
     return _expando; 
    } 

    public AttributeCollection GetAttributes() 
    { 
     return TypeDescriptor.GetAttributes(this, true); 
    } 

    public object GetEditor(Type editorBaseType) 
    { 
     return TypeDescriptor.GetEditor(this, editorBaseType, true); 
    } 

    public PropertyDescriptor GetDefaultProperty() 
    { 
     return null; 
    } 

    // This is where the GetProperties() calls are 
    // Ignore the Attribute for now, if it's needed support will have to be implemented 
    // Should be enough for simple usage... 

    PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() 
    { 
     return ((ICustomTypeDescriptor)this).GetProperties(new Attribute[0]); 
    } 

    public PropertyDescriptorCollection GetProperties(Attribute[] attributes) 
    { 
     // This just casts the ExpandoObject to an IDictionary<string, object> to get the keys 
     return new PropertyDescriptorCollection(
      ((IDictionary<string, object>)_expando).Keys 
      .Select(x => new ExpandoPropertyDescriptor(((IDictionary<string, object>)_expando), x)) 
      .ToArray()); 
    } 

    // A nested PropertyDescriptor class that can get and set properties of the 
    // ExpandoObject dynamically at run time 
    private class ExpandoPropertyDescriptor : PropertyDescriptor 
    { 
     private readonly IDictionary<string, object> _expando; 
     private readonly string _name; 

     public ExpandoPropertyDescriptor(IDictionary<string, object> expando, string name) 
      : base(name, null) 
     { 
      _expando = expando; 
      _name = name; 
     } 

     public override Type PropertyType 
     { 
      get { return _expando[_name].GetType(); } 
     } 

     public override void SetValue(object component, object value) 
     { 
      _expando[_name] = value; 
     } 

     public override object GetValue(object component) 
     { 
      return _expando[_name]; 
     } 

     public override bool IsReadOnly 
     { 
      get 
      { 
       // You might be able to implement some better logic here 
       return false; 
      } 
     } 

     public override Type ComponentType 
     { 
      get { return null; } 
     } 

     public override bool CanResetValue(object component) 
     { 
      return false; 
     } 

     public override void ResetValue(object component) 
     { 
     } 

     public override bool ShouldSerializeValue(object component) 
     { 
      return false; 
     } 

     public override string Category 
     { 
      get { return string.Empty; } 
     } 

     public override string Description 
     { 
      get { return string.Empty; } 
     } 
    } 
} 
+0

Đó là tuyệt vời nhưng tôi thực sự gửi ExpandoObject của tôi vào thư viện bên ngoài và ExpandoObj được niêm phong vì vậy tôi không thể kế thừa từ nó. Vì vậy, làm thế nào để tôi nói với nó để sử dụng thực hiện của riêng tôi của ICustomTypeDescriptor sau đó ...? –

+2

Ah, tôi không hiểu rõ vấn đề. Tôi nghĩ rằng lừa sẽ tạo ra một lớp bổ sung, một thực thi 'TypeDescriptionProvider'. Nó có một phương thức 'GetTypeDescriptor()' (với một số quá tải) trả về một 'ICustomTypeDescriptor' cho một đối tượng hoặc kiểu đã cho. Rig lên để trả về một thể hiện của 'ExpandoTypeDescriptor' ở trên. Sau đó đăng ký nhà cung cấp bằng cách sử dụng 'TypeDescriptor.AddProvider()'. Tôi nghĩ rằng sẽ có được tất cả mọi thứ làm việc cùng nhau. Điều đó có ý nghĩa? – daveaglick

+0

Tôi sẽ đánh dấu câu trả lời của bạn là câu trả lời chính xác vì nó đã làm việc với những thứ bạn đã thêm vào trong các ý kiến ​​... Tôi sẽ chỉnh sửa câu hỏi của mình để làm nổi bật điều đó. tnx !! –

Các vấn đề liên quan