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

时间:2020-03-06 14:43:46  来源:igfitidea点击:

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

好的,可能还不太清楚。让我通过我想拥有一个CollectionCollection <T>的代码媒介来解释这一点,如下所示:

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(blah)/ dataGridView1.Columns [blah] .ReadOnly = true"答案!!

帮助!

解决方案

Castle.DynamicProxy将完成此任务。
我们将要做的是创建一个继承T的拦截器。我们将存储隐藏和只读属性的集合。调用getter或者setter时,拦截器将检查该属性是否存在于任何一个集合中,然后采取适当的措施。

但是,我不知道我们将如何隐藏财产。我们不能在派生类中更改基类的访问修饰符。我们也许可以使用new关键字,但是我不知道如何使用Castle.DynamicProxy来做到这一点。

我们甚至无法隐藏属性,即使创建子类的代理也是如此。我们至少可以动态地构造一个具有良好属性的不同类型,但它不是T。

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

我决定采取不同的方法来解决这个问题,我真的没有看到树木成树木!我决定创建一个扩展方法,将我的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;
}