A Function That Compares the Properties of Two Objects

O

orekinbck

Hi There

I am learning about reflection so apologies if this post is vague ...

I am doing some unit testing and have written a function that accepts
two objects and tests to see if their properties are equal. It seems
to work OK except when a object has a property that is an array.

The GetValue method of the PropertyInfo class returns an object, and I
want to convert it to an array of objects. For some reason, this
fails:

object[] objectArray = (object[])myObject;

However if I know the type, then it works. For example:

SecurityRoles[] rolesArray = (SecurityRoles[])object;

The problem is that I don't know the type at design time ! I tried to
do this:

propInfo.PropertyType[] objectArray =
(propInfo.PropertyType[])myObject;

But it did not compile (ps ... propInfo is an instance of the
PropertyInfo class).

The code listing for my function is below. I would really appreciate
any guidance!

Thanks
Bill

using System;
using System.Reflection;

namespace ServerTest
{
public static class ObjectComparer
{
/// <summary>
/// This function compares any two objects properties. It will
recursively search down through nested properties
/// WARNING - It only compares properties that are one of the
following string, char, short, int, long, bool, DateTime, Enum
/// *** IT IGNORES ANY PROPERTIES THAT ARE ARRAYS ***
/// </summary>
/// <param name="thisType">The type of the two objects</param>
/// <param name="leftObject"></param>
/// <param name="rightObject"></param>
/// <returns>True to indicate that the objects are equal.
False otherwise</returns>
public static bool AreTheseObjectEqual(Type thisType, object
leftObject, object rightObject)
{
if (leftObject == null && rightObject == null)
return true;

if (leftObject == null || rightObject == null)
return false;

PropertyInfo[] fields = thisType.GetProperties();

foreach (PropertyInfo propInfo in fields)
{
if (propInfo.PropertyType.IsArray)
{


//*********************************************************************************
//Property is an array, need to iterate through the
elements and compare them

//*********************************************************************************

//object lhs = propInfo.GetValue(leftObject, null);
//object rhs = propInfo.GetValue(rightObject,
null);

////This does not work
//object[] lhsArray = (object[])lhs;
//object[] rhsArray = (object[])rhs;

////If the above worked, I could then do this:
//if (lhsArray.Length != rhsArray.Length)
// return false;
//else
//{
// for (int i = 0; i < lhsArray.Length; i++)
// {
// if (false ==
AreTheseObjectEqual(propInfo.PropertyType,
(object)lhsArray,(object)rhsArray))
// return false;
// }
//}

//BUT .... If I knew the type then this would
work:
//STE.Model.SecurityRoles[] secRolesLHS =
(STE.Model.SecurityRoles[])lhs;
//STE.Model.SecurityRoles[] secRolesRHS =
(STE.Model.SecurityRoles[])rhs;
//But I don't know the type at run time
}
else
{
object lhs = propInfo.GetValue(leftObject, null);
object rhs = propInfo.GetValue(rightObject, null);

if (propInfo.PropertyType.IsEnum)
{
if (lhs.ToString() != rhs.ToString())
return false;
}
else if (lhs is string)
{
if (false == rhs is string)
return false;
if ((string)lhs != (string)rhs)
return false;
}
else if (lhs is char)
{
if (false == rhs is char)
return false;
if ((char)lhs != (char)rhs)
return false;
}
else if (lhs is bool)
{
if (false == rhs is bool)
return false;
if ((bool)lhs != (bool)rhs)
return false;
}
else if (lhs is short)
{
if (false == rhs is short)
return false;
if ((long)lhs != (long)rhs)
return false;
}
else if (lhs is int)
{
if (false == rhs is int)
return false;
if ((int)lhs != (int)rhs)
return false;
}
else if (lhs is long)
{
if (false == rhs is long)
return false;
if ((long)lhs != (long)rhs)
return false;
}
else if (lhs is DateTime)
{
if (false == rhs is DateTime)
return false;
if ((DateTime)lhs != (DateTime)rhs)
return false;
}
else
{
PropertyInfo[] nestedFields =
propInfo.PropertyType.GetProperties();
if (nestedFields.Length > 0)
{
if (false ==
AreTheseObjectEqual(propInfo.PropertyType,
propInfo.GetValue(leftObject, null), propInfo.GetValue(rightObject,
null)))
return false;
}
}
}
}
return true;
}
}
}
 
G

Guest

Thats not so hard to do:

//...

PropertyInfo[] fields = thisType.GetProperties();
foreach (PropertyInfo propInfo in fields) {

if (propInfo.PropertyType.IsArray) {
object val = propInfo.GetValue(angel, null);

IEnumerator ie = ((System.Array)val).GetEnumerator();
while(ie.MoveNext()) {
//Now we have the individual object in the array
Console.WriteLine(ie.Current.GetType().ToString());
}
}

//...
}
 
I

Ignacio Machin \( .NET/ C# MVP \)

Hi,


Ashura's post should solve your problem, I just want to remember you that if
a property has a reference type you are comparing references ( if both
instances refers to the very same instance, not two instances with same
values).


cheers,

--
Ignacio Machin,
ignacio.machin AT dot.state.fl.us
Florida Department Of Transportation



Hi There

I am learning about reflection so apologies if this post is vague ...

I am doing some unit testing and have written a function that accepts
two objects and tests to see if their properties are equal. It seems
to work OK except when a object has a property that is an array.

The GetValue method of the PropertyInfo class returns an object, and I
want to convert it to an array of objects. For some reason, this
fails:

object[] objectArray = (object[])myObject;

However if I know the type, then it works. For example:

SecurityRoles[] rolesArray = (SecurityRoles[])object;

The problem is that I don't know the type at design time ! I tried to
do this:

propInfo.PropertyType[] objectArray =
(propInfo.PropertyType[])myObject;

But it did not compile (ps ... propInfo is an instance of the
PropertyInfo class).

The code listing for my function is below. I would really appreciate
any guidance!

Thanks
Bill

using System;
using System.Reflection;

namespace ServerTest
{
public static class ObjectComparer
{
/// <summary>
/// This function compares any two objects properties. It will
recursively search down through nested properties
/// WARNING - It only compares properties that are one of the
following string, char, short, int, long, bool, DateTime, Enum
/// *** IT IGNORES ANY PROPERTIES THAT ARE ARRAYS ***
/// </summary>
/// <param name="thisType">The type of the two objects</param>
/// <param name="leftObject"></param>
/// <param name="rightObject"></param>
/// <returns>True to indicate that the objects are equal.
False otherwise</returns>
public static bool AreTheseObjectEqual(Type thisType, object
leftObject, object rightObject)
{
if (leftObject == null && rightObject == null)
return true;

if (leftObject == null || rightObject == null)
return false;

PropertyInfo[] fields = thisType.GetProperties();

foreach (PropertyInfo propInfo in fields)
{
if (propInfo.PropertyType.IsArray)
{


//*********************************************************************************
//Property is an array, need to iterate through the
elements and compare them

//*********************************************************************************

//object lhs = propInfo.GetValue(leftObject, null);
//object rhs = propInfo.GetValue(rightObject,
null);

////This does not work
//object[] lhsArray = (object[])lhs;
//object[] rhsArray = (object[])rhs;

////If the above worked, I could then do this:
//if (lhsArray.Length != rhsArray.Length)
// return false;
//else
//{
// for (int i = 0; i < lhsArray.Length; i++)
// {
// if (false ==
AreTheseObjectEqual(propInfo.PropertyType,
(object)lhsArray,(object)rhsArray))
// return false;
// }
//}

//BUT .... If I knew the type then this would
work:
//STE.Model.SecurityRoles[] secRolesLHS =
(STE.Model.SecurityRoles[])lhs;
//STE.Model.SecurityRoles[] secRolesRHS =
(STE.Model.SecurityRoles[])rhs;
//But I don't know the type at run time
}
else
{
object lhs = propInfo.GetValue(leftObject, null);
object rhs = propInfo.GetValue(rightObject, null);

if (propInfo.PropertyType.IsEnum)
{
if (lhs.ToString() != rhs.ToString())
return false;
}
else if (lhs is string)
{
if (false == rhs is string)
return false;
if ((string)lhs != (string)rhs)
return false;
}
else if (lhs is char)
{
if (false == rhs is char)
return false;
if ((char)lhs != (char)rhs)
return false;
}
else if (lhs is bool)
{
if (false == rhs is bool)
return false;
if ((bool)lhs != (bool)rhs)
return false;
}
else if (lhs is short)
{
if (false == rhs is short)
return false;
if ((long)lhs != (long)rhs)
return false;
}
else if (lhs is int)
{
if (false == rhs is int)
return false;
if ((int)lhs != (int)rhs)
return false;
}
else if (lhs is long)
{
if (false == rhs is long)
return false;
if ((long)lhs != (long)rhs)
return false;
}
else if (lhs is DateTime)
{
if (false == rhs is DateTime)
return false;
if ((DateTime)lhs != (DateTime)rhs)
return false;
}
else
{
PropertyInfo[] nestedFields =
propInfo.PropertyType.GetProperties();
if (nestedFields.Length > 0)
{
if (false ==
AreTheseObjectEqual(propInfo.PropertyType,
propInfo.GetValue(leftObject, null), propInfo.GetValue(rightObject,
null)))
return false;
}
}
}
}
return true;
}
}
}
 
S

S. Senthil Kumar

Unless of course, the reference type overloaded the equality operator.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top