views:

639

answers:

2

I'm attempting to compare a transient object graph to an NHibernate-persisted object graph. Unfortunately my code breaks where properties of type IList<T> are concerned. The code below works fine with instances of List<T>, because List<T> implements both IList<T> AND IList. Unfortunately, NHibernate's PersistentGenericBag only implements IList<T>.

IList list1 = (IList)prop1.GetValue(object1, null);
IList list2 = (IList)prop2.GetValue(object2, null);

If either object1 or object2 is a PersistentGenericBag, I get an error such as:

System.Reflection.TargetInvocationException : Exception has been thrown
by the target of an invocation.
  ----> System.InvalidCastException : Unable to cast object of type
'NHibernate.Collection.Generic.PersistentGenericBag`1[MyNamespace.MyClass]'
to type 'System.Collections.Generic.List`1[MyNamespace.MyClass]'.

Is there a reliable way to retrieve the PersistentGenericBag instance as an IList<T> using reflection?

I had hoped the popular Compare .NET Objects class would help, but it fails with the exact same error.

Edit: All the answers below are on the right track. The problem was that the getter on the problematic IList<T> property was attempting a cast to List<T>, which obviously can't be done to a PersistentGenericBag. So, my fault for the misguided question.

+1  A: 

You don't need an IList to compare two collections.

Cast to IEnumerable instead.

Diego Mijelshon
For whatever reason, "(IEnumerable)prop1.GetValue(object1, null);" yields the exact same error.
nw
Are you sure prop1 and object1 are the property and object you are looking for? Did you look at them (and the invocation result) in the debugger?
Diego Mijelshon
+1  A: 

EDIT: never mind. commenter is right, you CAN go straight to IList. I was focusing one the question as stated a little too hard to see the obvious even as I was coding the answer. doh!

Ok, you just need to dig a little bit deeper.

The base class of PersistentGenericBag is PersistentBag, which does implement IList.

var prop1 = typeof (Customer).GetProperty("Invoice");

// if you need it for something...
var listElementType = prop1.PropertyType.GetGenericArguments()[0];

IList list1;


object obj = prop1.GetValue(object1, null);

if(obj is PersistentBag)
{
    list1 = (PersistentBag)obj;
}
else 
{
    list1 = (IList)obj;
}

foreach (object item in list1)
{
    // do whatever you wanted.
}

Tested and works for bags. Take it to the logical conclusion for other list/set/collection types that you might encounter.

So, the short answer is; If you KNOW it is a bag, you can just cast the object first to PersistentBag and then to IList...

IList list = (PersistentBag)obj;

If you DONT KNOW then use some conditional logic as shown.

Sky Sanders