How to convert an object from Reflection to a shared collection?

I am trying to write a Compare method to compare properties in some POCOs using Reflection, to make sure that they are stored in the database correctly. For example, let's say I have this POCO:

public class NoahsArk { public string Owner { get; set; } public ICollection<Animal> Animals { get; set; } } 

I want to do the following:

 [Test] public class Saves_Correctly_To_Database() { var noahsArk = new NoahsArk { // some setup code here }; db.Save(noahsArk); var dbNoahsArk = db.Get<NoahsArk>(noahsArk.Id); Assert.That(Compare(noahsArk, dbNoahsArk), Is.True); } 

The ORM that I use is NHibernate. My comparison method looks like this:

 public static bool EqualsProperties<T>(this T x, T y) { var xType = x.GetType(); foreach (var property in xType.GetProperties()) { if (property.GetValue(x, null).Implements(typeof(ICollection<>))) { var xValue = property.GetValue(x, null) as ICollection<T>; var yValue = property.GetValue(y, null) as ICollection<T>; } 

Object.Implements() is an extension method that I wrote to determine if a type implements an interface. As you can see, the method is incomplete. The problem I am facing is that when I use property.GetValue(x, null) , it returns an object , and I don't know how to pass it to its specific generic type ICollection . I need to do this so that I can use LINQ to execute x.Contains(y) to compare two collections for equality. Any idea on how to do this?

PS I tried using Compare .NET Objects , but it gives me an exception with a reference to null, somewhere deep inside NHibernate. It does not properly handle how NHibernate proxies ICollection for lazy loading. Worse, NHibernate modifies POCO to support lazy loading, but this is all done at runtime. In the source code, it looks like you're just working with a regular ICollection , but NHibernate changes this to NHibernate.Collections.Generic.PersistentSet at runtime, and this is what causes the comparator to fail.

+4
source share
2 answers

Your question is a bit confusing because you don't need a type parameter T in the declaration of your EqualsProperties method. You just need

 public static bool EqualsProperties(this object x, object y) 

Then you continue to use the same T parameter to distinguish the x and y properties to ICollection<T> ; however, the objects in these collections can obviously be of a different type than x and y.

Now, to answer your question: you do not need to specify the correct type of the generic type in order to use the LINQ Contains method. You can do something like this:

 xValue = property.GetValue(x, null); yValue = property.GetValue(y, null); if (typeof(IEnumerable).IsInstanceOf(x)) { IEnumerable<object> xEnumerable = (x as IEnumerable).Cast<object>(); IEnumerable<object> yEnumerable = (y as IEnumerable).Cast<object>(); // use any LINQ method you like now } 

You should also make sure that you use LINQ overloads that use the equalizer, since your domain objects obviously do not override the Equals method. Otherwise, you will not write this device testing code to compare them.

+2
source

The Sharp architecture framework uses the attribute for decor properties that should be accepted into the equals method. See Source Code for DomainSignatureAttribute and EntityWithTypedId<>.Equals .

0
source

All Articles