Tuesday, February 8, 2011

Obtaining a collection of constructed subclassed types using reflection

I want to create a class which implements IEnumerable<T> but, using reflection, generates T's and returns them via IEnumerable<T>, where T' is a entirely constructed subclass of T with some properties hidden and others read-only.

Okay., that might not be very clear. Let me explain this via the medium of code - I'd like to have a class CollectionView<T> as follows:-

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;

(When displayed in dataGridView1 shows columns B and C and C has an underlying store which is read-only)

Is this possible/desirable or have I completely lost my mind/does this question demonstrate my deep inadequacy as a programmer?

I want to do this so I can manipulate a collection that is to be passed into a DataGridView, without having to directly manipulate the DataGridView to hide columns/make columns read-only. So no 'oh just use dataGridView1.Columns.Remove(blah) / dataGridView1.Columns[blah].ReadOnly = true' answers please!!

Help!

  • Castle.DynamicProxy will help you accomplish this. What you would do is create an interceptor that inherits T. You would store the collection of hidden and read-only properties. When a getter or setter is called, the interceptor would check to see if the property exists in either collection and then take appropriate action.

    However, I know not how you would hide a property. You cannot change the access modifier of a base class in a derived class. You MAY be able to use the new keyword, but I know not how to do that with Castle.DynamicProxy.

    From Gilligan
  • You just can't hide properties, even by creating subclassed proxies. You could at least construct a different type dynamically, which holds good properties, but it would not be a T.

    But returning an object list could be sufficient if you just need to use databinding.

  • I decided to take a different approach to this problem, I really wasn't seeing the wood for the trees! I decided to create an extension method which converts my IEnumerable to a data table which can then be passed around as required:-

    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;
    }
    
    From kronoz

0 comments:

Post a Comment