473,387 Members | 1,553 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

Reflecting generic collections of derived types

I am trying to use reflection in a property of a base type to inspect the properties of an instance of a type which is derived from that base type, when the properties can themselves be instances of types derived from that base type, or arrays or generic collections of instances of types derived from that base type.

All is well until I come to the properties which are generic collections, I don't seem to be able to find an elegant way of inspecting these.

Here is some code to illustrate what I'm trying to do. The base type, and therefore the derived types, have an ErrorState property, this is an enumeration of things which could be wrong with instances of those types. There is also a ConsolidatedState property, this is the one which uses reflection to return a combination of all the things which may be wrong with the current instance and all of its properties.

Expand|Select|Wrap|Line Numbers
  1.  
  2. [Flags]
  3. public enum ErrorState
  4. {
  5.     Ok = 1,
  6.     ConnectionError = 2,
  7.     HoustonWeHaveAProblem = 4
  8.     // etc...
  9. }
  10.  
  11. public abstract class MyBase
  12. {
  13.     private ErrorState _errorState;
  14.  
  15.     public ErrorState ErrorState
  16.     {
  17.         get { return _errorState; }
  18.         set { _errorState = value; }
  19.     }
  20.  
  21.     public ErrorState ConsolidatedState
  22.     {
  23.         get
  24.         {
  25.             ErrorState state = this.ErrorState;
  26.             PropertyInfo[] properties = this.GetType().GetProperties();
  27.             foreach( PropertyInfo property in properties )
  28.             {
  29.                 // We don't want to inspect the ConsolidatedState property
  30.                 // (this property) else we get stuck in a loop, causing a
  31.                 // StackOverflowException.
  32.                 if( property.Name == "ConsolidatedState" )
  33.                 {
  34.                     continue;
  35.                 }
  36.  
  37.                 // Is this property an array?
  38.                 if( property.PropertyType.IsArray )
  39.                 {
  40.                     // Is this property an array of objects derived from 
  41.                     // MyBase?
  42.                     MyBase[] componentArray 
  43.                         = property.GetValue( this, null ) as MyBase[];
  44.                     if( componentArray != null )
  45.                     {
  46.                         // Yes, so inspect their ConsolidatedState properties.
  47.                         foreach( MyBase c in componentArray )
  48.                         {
  49.                             state |= c.ConsolidatedState;
  50.                         }
  51.                     }
  52.                     continue;
  53.                 }
  54.  
  55.                 // Is this property an indexer?
  56.                 if( property.GetIndexParameters().Length > 0 )
  57.                 {
  58.                     // it's probably an indexer, so ignore it
  59.                     continue;
  60.                 }
  61.  
  62.                 // Is this property of a type derived from MyBase?
  63.                 if( property.PropertyType.IsSubclassOf( typeof( MyBase ) ) )
  64.                 {
  65.                     // Yes, so it also has a ConsolidatedState property
  66.                     MyBase component 
  67.                         = property.GetValue( this, null ) as MyBase;
  68.                     if( component != null )
  69.                     {
  70.                         state |= component.ConsolidatedState;
  71.                     }
  72.                     continue;
  73.                 }
  74.  
  75.                 // Is this property a generic type?
  76.                 if( property.PropertyType.IsGenericType )
  77.                 {
  78.                     // Is this property a generic collection of a type
  79.                     // derived from MyBase?
  80.                     //Collection<MyBase> componentCollection
  81.                     //    = property.GetValue( this, null ) 
  82.                     //    as Collection<MyBase>; // returns null
  83.  
  84.                     // Is this property a generic collection of MyDerived1?
  85.                     IEnumerable<MyDerived1> componentCollection 
  86.                         = property.GetValue( this, null )
  87.                         as IEnumerable<MyDerived1>;
  88.                     if( componentCollection != null )
  89.                     {
  90.                         // Yes, so inspect their ConsolidatedState properties.
  91.                         foreach( MyBase c in componentCollection )
  92.                         {
  93.                             state |= c.ConsolidatedState;
  94.                         }
  95.                     }
  96.                     continue;
  97.                 }
  98.  
  99.             }
  100.             return state;
  101.         }
  102.     }
  103. }
  104.  
  105. public class MyDerived1 : MyBase
  106. {
  107.     // ...
  108. }
  109.  
  110. public class MyDerived2 : MyBase
  111. {
  112.     public MyDerived1 Property1
  113.     {
  114.         get { return new MyDerived1(); }
  115.     }
  116.  
  117.     public MyDerived1[] Property2
  118.     {
  119.         get { return new MyDerived1[4]; }
  120.     }
  121.  
  122.     public Collection<MyDerived1> Property3
  123.     {
  124.         get { return new Collection<MyDerived1>(); }
  125.     }
  126. }
  127.  
  128.  
The problem is with this line, which I've commented out in the ConsolidatedState property of MyBase:

// Is this property a generic collection of a type
// derived from MyBase?
Collection<MyBase> componentCollection
= property.GetValue( this, null )
as Collection<MyBase>; // returns null

Having determined that the property being inspected is a generic collection, I want to know whether the items in the collection are of a type which is derived from MyBase and therefore has an ErrorState.

Having read Casting generic collections & inheritance in the archive forum, I understand now why the cast above doesn't work. As one of the contributors to that thread succinctly puts it, a List of (Farmers) is also a List of (Persons), but a (List of Farmers) is not a (List of Persons), and I'm trying to cast a (List of Farmers) to a (List of Persons).

What I want to do is attempt to cast something which I know is a generic collection, into any sort of array / list / collection in order that I can determine whether its items are derived from MyBase and therefore whether they have a ConsolidatedState property.

As you can see, I came up with a solution, but it's not very elegant because it depends on MyBase knowing that one or more of its derived types has a property which is a generic collection of instances of another specific type derived from MyBase. If someone later writes another type derived from MyBase, with a property which is a generic collection of instances of a type other than MyDerived1, then its ConsolidatedState property won't be able to inspect that collection unless MyBase is also changed to cater for properties of that type.

I feel sure that there must be a more elegant solution than this, one in which the author of MyBase doesn't need to know any of the implementation details of any of the types derived from MyBase. Can anyone suggest one?

Thank you and apologies for a long first post.

Simon.
Jul 18 '09 #1
2 4148
Just check if the property is IEnumerable (non-generic version) and then cast objects to whatever you want. That way you will cover arrays too because arrays are IEnumerable.
Aug 5 '09 #2
@icesign
Thank you!

I changed the lines within the ConsolidatedState property

Expand|Select|Wrap|Line Numbers
  1. // Is this property a generic collection of MyDerived1?
  2. IEnumerable<MyDerived1> componentCollection 
  3.     = property.GetValue( this, null )
  4.     as IEnumerable<MyDerived1>;
  5. if( componentCollection != null )
  6. {
  7.     // Yes, so inspect their ConsolidatedState properties.
  8.     foreach( MyBase c in componentCollection )
  9.     {
  10.         state |= c.ConsolidatedState;
  11.     }
  12. }
  13.  
to

Expand|Select|Wrap|Line Numbers
  1. // Is this property IEnumerable?
  2. IEnumerable objectCollection 
  3.     = property.GetValue( this, null ) as IEnumerable;
  4. if( objectCollection != null )
  5. {
  6.     // Yes, it's IEnumerable, so iterate through its items
  7.     foreach( object o in objectCollection )
  8.     {
  9.         // Is this item of a type derived from MyBase?
  10.         MyBase c = o as MyBase;
  11.         if( c != null )
  12.         {
  13.             // Yes, so get its ConsolidatedState property
  14.         state |= c.ConsolidatedState;
  15.         }
  16.     }
  17. }
  18.  
and it all seems to work fine now.

Thank you Icesign :-)
Aug 6 '09 #3

Sign in to post your reply or Sign up for a free account.

Similar topics

1
by: Andy | last post by:
Can anyone tell me if it is possible to dynamically create generic collections? simply put I want to be able to something like this : public object test(SomeBaseClass param1) { if...
2
by: Jasper Kent | last post by:
I'm trying to do the equivalent of using typedefs with templates in C++ to avoid long instantiation names. I can do this okay: using BigDictionary = System.Collections.Generic.Dictionary<int,...
2
by: ljlevend | last post by:
I've noticed that in VS.NET 2.0 Beta 1 that none of the methods in System.Collections.Generic.List are overridable. In my app I currently have over 50 strongly typed ArrayLists that inherit from...
22
by: Adam Clauss | last post by:
OK, I have class A defined as follows: class A { A(Queue<B> queue) { ... } } Now, I then have a subclass of both classes A and B. The subclass of A (SubA), more specifically is passed a...
5
by: Dale | last post by:
I read an article sometime in the last few weeks comparing the performance of Generic Collections to ArrayList. It was pretty detailed with several charts comparing various collections methods...
1
by: Ralf Propach | last post by:
Hi, in C# I can write Type listType = typeof(System.Collections.Generic.List<>); What is the equivalent in C++? I get compiler errors for all of the following: Type listType =...
3
by: Boris | last post by:
I have a class which should like this ideally: generic <typename T> public ref class ManagedClass { T ^managedMember; UnmanagedClass<U*unmanagedMember; }; I actually would like to specify...
26
by: raylopez99 | last post by:
Here is a good example that shows generic delegate types. Read this through and you'll have an excellent understanding of how to use these types. You might say that the combination of the generic...
0
by: SimonDotException | last post by:
I've written an abstract base type which uses generics to provide XML serialization and deserialization methods for use by its derived types, but I'm seemingly unable to write it in a way which...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.