代码之家  ›  专栏  ›  技术社区  ›  ljs TheVillageIdiot

使用反射获取构造的子类类型的集合

  •  0
  • ljs TheVillageIdiot  · 技术社区  · 16 年前

    我想创建一个实现IEnumerable<T>的类,但是使用反射,生成T并通过IEnumerable<T>返回它们,其中T'是完全构造的T子类,其中一些属性隐藏,而其他属性是只读的。

    好吧,那可能不太清楚。让我通过代码的媒介来解释这一点-我希望有一个类集合视图<T>as以下内容:-

    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。列。删除(blah)/dataGridView1.Columns[blah].ReadOnly=true'请回答!!

    救命啊!

    4 回复  |  直到 16 年前
        1
  •  1
  •   Gilligan    16 年前

    Castle.DynamicProxy 会帮助你完成这个任务。 您要做的是创建一个继承T的拦截器,您将存储隐藏和只读属性的集合。当调用getter或setter时,拦截器将检查两个集合中是否存在该属性,然后采取适当的操作。

    但是,我不知道你会怎么隐藏财产。不能更改派生类中基类的访问修饰符。您可以使用 new

        2
  •  0
  •   Romain Verdier    16 年前

    即使创建子类代理,也不能隐藏属性。您至少可以动态构造一个不同的类型,它具有良好的属性,但它不会是 T .

    但是,如果只需要使用数据绑定,返回一个对象列表就足够了。

        3
  •  0
  •   ljs TheVillageIdiot    16 年前

    我决定用另一种方法来解决这个问题,我真的不是见死不救!我决定创建一个扩展方法,将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;
    }
    
        4
  •  0
  •   Stephen    12 年前

    也可以使用ICustomTypeDescriptor来筛选属性列表。为此,我为数据对象创建了一个包装类(MyWrapper)、一个自定义属性描述符(MypropertyDescriptor)和集合类。我扩展了collection类,使之也能观察IList,以便可以修改数据;扩展了ITypedList,以便datagrid可以构建列。您可能还希望继承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();
        }
    }
    

    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
    }