2008-09-25 38 views
0

我想創建一個實現IEnumerable類的類,但使用反射生成T並通過IEnumerable返回它們,其中T'是T的完全構造的子類一些屬性隱藏,其他屬性爲只讀。使用反射獲得構造的子類型類型的集合

好的,那可能不是很清楚。讓我通過代碼的介質解釋 - 我想有一個類的CollectionView <Ť>如下: -

public class CollectionView<T> : IEnumerable<T> { 
    public CollectionView(IEnumerable<T> inputCollection, 
    List<string> hiddenProperties, List<string> readonlyProperties) { 
    // ... 
    } 

    // IEnumerable<T> implementation which returns a collection of T' where T':T. 
} 

... 

public class SomeObject { 
    public A { get; set; } 
    public B { get; set; } 
    public C { get; set; } 
} 

... 

var hiddenProperties = new List<string>(new[] { "A" }); 
var readOnlyProperties = new List<string>(new[] { "C" }); 

IEnumerable<SomeObject> someObjects = CollectionView<SomeObject>(hiddenProperties, 
    readOnlyProperties); 

... 

dataGridView1.DataSource = someObjects; 

(當dataGridView1顯示示出了列B和C和C具有底層存儲其是隻讀的)

這是可能的/可取的,還是我完全失去了我的想法/這個問題表明我作爲程序員的深刻不足?

我想這樣做,所以我可以操縱要傳遞到DataGridView,而不必直接操縱DataGridView隱藏列/使列只讀的集合。所以沒有'哦只是使用dataGridView1.Columns.Remove(等等)/ dataGridView1.Columns [等等] .ReadOnly =真'的答案請!

幫助!

回答

1

Castle.DynamicProxy將幫助您完成此操作。 你會做的是創建一個繼承T的攔截器。你將存儲隱藏和只讀屬性的集合。當一個getter或setter被調用時,攔截器會檢查這個屬性是否存在於任何一個集合中,然後採取適當的行動。

但是,我不知道你會如何隱藏一個屬性。您不能在派生類中更改基類的訪問修飾符。您可以使用new關鍵字,但我不知道如何使用Castle.DynamicProxy做到這一點。

0

即使通過創建子類別的代理,您也無法隱藏屬性。你至少可以構造一個不同的類型,它具有很好的屬性,但它不會是T

但是,如果您只需要使用數據綁定,則返回對象列表就足夠了。

0

我決定採取不同的方法解決這個問題,我真的沒有看到樹木的木材!我決定建立它轉換我的IEnumerable來,然後可以繞過所需的數據表的擴展方法: -

public static DataTable ToDataTable<T>(this IEnumerable<T> collection) 
{ 
    DataTable ret = new DataTable(); 

    Type type = typeof(T); 

    foreach (PropertyInfo propertyInfo in type.GetProperties()) 
    { 
     // Ignore indexed properties. 
     if (propertyInfo.GetIndexParameters().Length > 0) continue; 
     ret.Columns.Add(propertyInfo.Name); 
    } 

    foreach (T data in collection) 
    { 
     DataRow row = ret.NewRow(); 
     foreach (PropertyInfo propertyInfo in type.GetProperties()) 
     { 
      // Ignore indexed properties. 
      if (propertyInfo.GetIndexParameters().Length > 0) continue; 

      row[propertyInfo.Name] = propertyInfo.GetValue(data, null); 
     } 

     ret.Rows.Add(row); 
    } 

    return ret; 
} 
0

您還可以使用ICustomTypeDescriptor過濾屬性列表。爲此,我爲數據對象(MyWrapper),自定義屬性描述符(MypropertyDescriptor)和集合類創建了一個包裝類。我擴展了集合類來觀察IList,以便可以修改數據,ITypedList使數據網格可以構建列。您可能還想要繼承ObservableCollection>或BindingList> <>。

自定義描述符是處理設置和檢索屬性值:

public sealed class MyPropertyDescriptor : System.ComponentModel.PropertyDescriptor 
{ 
    private PropertyDescriptor innerProperty; 
    private Boolean isReadonly; 

    public MyPropertyDescriptor(PropertyDescriptor innerProperty, Boolean isReadonly) 
     : base(innerProperty.Name, GetAttributeArray(innerProperty.Attributes)) 
    { 
     this.innerProperty = innerProperty; 
     this.isReadonly = isReadonly; 
     if (!isReadonly) this.isReadonly = innerProperty.IsReadOnly; 
    } 

    public override Type ComponentType 
    { 
     get { return this.innerProperty.ComponentType; } 
    } 
    public override Boolean IsReadOnly 
    { 
     get { return this.isReadonly; } 
    } 
    public override Type PropertyType 
    { 
     get { return this.innerProperty.PropertyType; } 
    } 
    public override String Name 
    { 
     get 
     { 
      return this.innerProperty.Name; 
     } 
    } 
    public override String DisplayName 
    { 
     get 
     { 
      return this.innerProperty.DisplayName; 
     } 
    } 
    public override Boolean SupportsChangeEvents 
    { 
     get 
     { 
      return true; 
     } 
    } 
    public override void SetValue(Object component, Object value) 
    { 
     if (!this.isReadonly) 
     { 
      this.innerProperty.SetValue(component, value); 
      if (component is MyWrapper) (component as MyWrapper).NotifyPropertyChanged(this.innerProperty.Name); 
     } 
    } 
    public override Object GetValue(Object component) 
    { 
     return this.innerProperty.GetValue(component); 
    } 

    public override Boolean CanResetValue(Object component) 
    { 
     return false; 
    } 
    public override void ResetValue(Object component) 
    { 
    } 
    public override Boolean ShouldSerializeValue(Object component) 
    { 
     return true; 
    } 

    private static Attribute[] GetAttributeArray(AttributeCollection attributes) 
    { 
     List<Attribute> attr = new List<Attribute>(); 
     foreach (Attribute a in attributes) attr.Add(a); 

     return attr.ToArray(); 
    } 
} 

包裝類是控制通過ICustomTypeDescriptor來訪問屬性:

public sealed class MyWrapper : System.ComponentModel.ICustomTypeDescriptor, System.ComponentModel.INotifyPropertyChanged 
{ 
    private Object innerObject; 
    private String[] hiddenProps; 
    private String[] readonlyProps; 

    private Type innerType; 

    public MyWrapper(Object innerObject, String[] hiddenProps, String[] readonlyProps) 
     : base() 
    { 
     this.innerObject = innerObject; 
     this.hiddenProps = hiddenProps; 
     this.readonlyProps = readonlyProps; 
     this.innerType = innerObject.GetType(); 
    } 

    public static PropertyDescriptorCollection FilterProperties(PropertyDescriptorCollection pdc, String[] hiddenProps, String[] readonlyProps) 
    { 
     List<PropertyDescriptor> list = new List<PropertyDescriptor>(); 

     foreach (PropertyDescriptor pd in pdc) 
     { 
      if (hiddenProps != null) 
      { 
       Boolean isHidden = false; 
       foreach (String hidden in hiddenProps) 
       { 
        if (hidden.Equals(pd.Name, StringComparison.OrdinalIgnoreCase)) 
        { 
         isHidden = true; 
         break; 
        } 
       } 
       if (isHidden) continue; // skip hidden 
      } 

      Boolean isReadonly = false; 
      if (readonlyProps != null) 
      { 
       foreach (String rp in readonlyProps) 
       { 
        if (rp.Equals(pd.Name, StringComparison.OrdinalIgnoreCase)) 
        { 
         isReadonly = true; 
         break; 
        } 
       } 
      } 

      list.Add(new MyPropertyDescriptor(pd, isReadonly)); 
     } 

     return new PropertyDescriptorCollection(list.ToArray()); 
    } 

    #region ICustomTypeDescriptor Members 

    PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes) 
    { 
     return FilterProperties(TypeDescriptor.GetProperties(this.innerType, attributes), hiddenProps, readonlyProps); 
    } 
    PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() 
    { 
     return FilterProperties(TypeDescriptor.GetProperties(this.innerType), hiddenProps, readonlyProps); 
    } 

    AttributeCollection ICustomTypeDescriptor.GetAttributes() 
    { 
     return TypeDescriptor.GetAttributes(this.innerType); 
    } 

    String ICustomTypeDescriptor.GetClassName() 
    { 
     return TypeDescriptor.GetClassName(this.GetType()); 
    } 
    String ICustomTypeDescriptor.GetComponentName() 
    { 
     return TypeDescriptor.GetComponentName(this.GetType()); 
    } 
    TypeConverter ICustomTypeDescriptor.GetConverter() 
    { 
     return TypeDescriptor.GetConverter(this.GetType()); 
    } 
    EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() 
    { 
     return TypeDescriptor.GetDefaultEvent(this.GetType()); 
    } 
    PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() 
    { 
     return null; 
    } 
    Object ICustomTypeDescriptor.GetEditor(Type editorBaseType) 
    { 
     return TypeDescriptor.GetEditor(this.GetType(), editorBaseType); 
    } 
    EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes) 
    { 
     return null; 
    } 
    EventDescriptorCollection ICustomTypeDescriptor.GetEvents() 
    { 
     return null; 
    } 

    Object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd) 
    { 
     return this.innerObject; 
    } 

    #endregion 

    #region INotifyPropertyChanged Members 
    internal void NotifyPropertyChanged(String propertyName) 
    { 
     if (this.propertyChanged != null) this.propertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 
    private event PropertyChangedEventHandler propertyChanged; 
    event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged 
    { 
     add { propertyChanged += value; } 
     remove { propertyChanged -= value; } 
    } 
    #endregion 
} 

和修改後的版本的CollectionView <>。該示例的大部分內容僅將接口方法映射到內部列表。

public sealed class CollectionView<T> : IEnumerable<MyWrapper>, System.Collections.IList, IList<MyWrapper>, ITypedList 
{ 
    private String[] hiddenProps; 
    private String[] readonlyProps; 
    private List<MyWrapper> collection; 

    public CollectionView(IEnumerable<T> innerCollection, String[] hiddenProps, String[] readonlyProps) 
     : base() 
    { 
     this.hiddenProps = hiddenProps; 
     this.readonlyProps = readonlyProps; 

     this.collection = new List<MyWrapper>(); 
     foreach (T item in innerCollection) 
     { 
      this.collection.Add(new MyWrapper(item, hiddenProps, readonlyProps)); 
     } 
    } 

    #region ITypedList Members 

    PropertyDescriptorCollection ITypedList.GetItemProperties(PropertyDescriptor[] listAccessors) 
    { 
     return MyWrapper.FilterProperties(TypeDescriptor.GetProperties(typeof(T)), this.hiddenProps, this.readonlyProps); 
    } 

    String ITypedList.GetListName(PropertyDescriptor[] listAccessors) 
    { 
     return null; 
    } 
    #endregion 

    #region IEnumerable<MyWrapper> Members 

    IEnumerator<MyWrapper> IEnumerable<MyWrapper>.GetEnumerator() 
    { 
     return this.collection.GetEnumerator(); 
    } 

    #endregion 

    #region IEnumerable Members 

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
    { 
     return this.collection.GetEnumerator(); 
    } 

    #endregion 

    #region IList Members 
    Int32 System.Collections.IList.Add(Object value) 
    { 
     return (this.collection as System.Collections.IList).Add(value); 
    } 
    void System.Collections.IList.Clear() 
    { 
     (this.collection as System.Collections.IList).Clear(); 
    } 
    Boolean System.Collections.IList.Contains(Object value) 
    { 
     return (this.collection as System.Collections.IList).Contains(value); 
    } 
    Int32 System.Collections.IList.IndexOf(Object value) 
    { 
     return (this.collection as System.Collections.IList).IndexOf(value); 
    } 
    void System.Collections.IList.Insert(Int32 index, Object value) 
    { 
     (this.collection as System.Collections.IList).Insert(index, value); 
    } 
    Boolean System.Collections.IList.IsFixedSize 
    { 
     get { return (this.collection as System.Collections.IList).IsFixedSize; } 
    } 
    Boolean System.Collections.IList.IsReadOnly 
    { 
     get { return (this.collection as System.Collections.IList).IsReadOnly; } 
    } 
    void System.Collections.IList.Remove(Object value) 
    { 
     (this.collection as System.Collections.IList).Remove(value); 
    } 
    void System.Collections.IList.RemoveAt(Int32 index) 
    { 
     (this.collection as System.Collections.IList).RemoveAt(index); 
    } 
    Object System.Collections.IList.this[Int32 index] 
    { 
     get 
     { 
      return (this.collection as System.Collections.IList)[index]; 
     } 
     set 
     { 
      (this.collection as System.Collections.IList)[index] = value; 
     } 
    } 
    #endregion 

    #region ICollection Members 
    void System.Collections.ICollection.CopyTo(Array array, Int32 index) 
    { 
     (this.collection as System.Collections.ICollection).CopyTo(array, index); 
    } 
    Int32 System.Collections.ICollection.Count 
    { 
     get { return (this.collection as System.Collections.ICollection).Count; } 
    } 
    Boolean System.Collections.ICollection.IsSynchronized 
    { 
     get { return (this.collection as System.Collections.ICollection).IsSynchronized; } 
    } 
    Object System.Collections.ICollection.SyncRoot 
    { 
     get { return (this.collection as System.Collections.ICollection).SyncRoot; } 
    } 
    #endregion 

    #region IList<MyWrapper> Members 
    Int32 IList<MyWrapper>.IndexOf(MyWrapper item) 
    { 
     return this.collection.IndexOf(item); 
    } 
    void IList<MyWrapper>.Insert(Int32 index, MyWrapper item) 
    { 
     this.collection.Insert(index, item); 
    } 
    void IList<MyWrapper>.RemoveAt(Int32 index) 
    { 
     this.collection.RemoveAt(index); 
    } 
    MyWrapper IList<MyWrapper>.this[Int32 index] 
    { 
     get 
     { 
      return this.collection[index]; 
     } 
     set 
     { 
      this.collection[index] = value; 
     } 
    } 
    #endregion 

    #region ICollection<MyWrapper> Members 
    void ICollection<MyWrapper>.Add(MyWrapper item) 
    { 
     this.collection.Add(item); 
    } 
    void ICollection<MyWrapper>.Clear() 
    { 
     this.collection.Clear(); 
    } 
    Boolean ICollection<MyWrapper>.Contains(MyWrapper item) 
    { 
     return this.collection.Contains(item); 
    } 
    void ICollection<MyWrapper>.CopyTo(MyWrapper[] array, Int32 arrayIndex) 
    { 
     this.collection.CopyTo(array, arrayIndex); 
    } 
    Int32 ICollection<MyWrapper>.Count 
    { 
     get { return this.collection.Count; } 
    } 
    Boolean ICollection<MyWrapper>.IsReadOnly 
    { 
     get { return false; } 
    } 
    Boolean ICollection<MyWrapper>.Remove(MyWrapper item) 
    { 
     return this.collection.Remove(item); 
    } 
    #endregion 
}