Hello all,
I just thought that I would drop in and leave a simple starting point for people, if they wanted to try to perform some equal operations. This isn't a fully fleshed out class, but I wanted to give a decent starting point for people that needed something generic, but never had the time to sit and write it. Again, it isn't complete (and to many readers may very well be overly simplistic), but it should work with its limited set of operations... albeit slowly with large sets of data, since it checks all values.
I hope this is helpful:
The equal classes
very simple class and implementation for above
If anyone has any recommendations/add ons, by all means drop them on here..it is a community forum.
-Kevin
- "The truth hurts, maybe not as much as jumping on a bicycle with no seat, but it hurts.
I just thought that I would drop in and leave a simple starting point for people, if they wanted to try to perform some equal operations. This isn't a fully fleshed out class, but I wanted to give a decent starting point for people that needed something generic, but never had the time to sit and write it. Again, it isn't complete (and to many readers may very well be overly simplistic), but it should work with its limited set of operations... albeit slowly with large sets of data, since it checks all values.
I hope this is helpful:
The equal classes
Code:
using System;
using System.Collections;
using System.Collections.Specialized;
namespace GenericEqual
{
public class _Equals
{
//Its always nice not to have to recreate an object
//every time you want to use it, so I use the following
//for singletons
//(I recommend making _Equals() private if you do)
public static _Equals Instance = new _Equals();
//Use the following to instantiate your own copy
public _Equals() {}
#region Publicly Exposed Methods
//Public
/*
public bool MyTypesAreEqual( object val1, object val2 )
{
//Just in case
if ( !IsMyType(val1.GetType()) || !IsMyType(val2.GetType()) )
return false;
MyType mt1 = (val1 as MyType);
MyType mt2 = (val2 as MyType);
if (mt1 == null && mt2 == null)
return true; //If both are null, they seem equal
else if (mt1 == null || mt2 == null)
return false; //If only one is null, they aren't equal
//Add you own custom check stuff here
//Use ValuesAreEqual for anything that is already handled
if (!ValuesAreEqual( mt1.MyString1, mt2.Mystring2 ))
return false;
//...
}
public bool MyType2sAreEqual( object val1, object val2 )
{
//Just in case...keeps from having a false-positive
//Equal. If this weren't here, if you passed any
//objects of any OTHER type, they would pass the
//null equal check below
if ( !IsMyType(val1.GetType()) || !IsMyType(val2.GetType()) )
return false;
MyType2 mt1 = (val1 as MyType);
MyType2 mt2 = (val2 as MyType);
//If they are null, they seem equal
if (mt1 == null && mt2 == null)
return true;
else if (mt1 == null || mt2 == null)
return false; //If only one is null, they aren't equal
//Add you own custom check stuff here
//Use ValuesAreEqual for anything that is already handled
if (!ValuesAreEqual( mt1.MyString1, mt2.Mystring2 ))
return false;
//...
}
*/
public bool ValuesAreEqual( object val1, object val2 )
{
if (val1 == null && val2 == null)
return true;
else if (val1 == null || val2 == null)
return false;
if (!val1.GetType().Equals(val2.GetType()))
return false;
switch ( GetCompareType(val1.GetType()) )
{
//Add Code Here
//case "MYTYPE": return MyTypesAreEqual(val1, val2);
//case "MYTYPE2": return MyType2sAreEqual(val1, val2);
case "ARRAY": return ArraysAreEqual(val1, val2);
case "ARRAYLIST": return ArrayListsAreEqual(val1, val2);
case "HASHTABLE": return HashtablesAreEqual(val1, val2);
case "COMPARABLE": return (val1.Equals(val2));
default: return true; //Unhandled data type, return true
}
}
#endregion
#region Private Comparison Methods
//You may want to expose these as well, its mostly a preference,
//but in the case where you always know exactly what the object
//you want to compare is, this will remove the extra overhead
//incurred by the extra conversions from the initial "ValuesAreEqual" call
//but I don't think this is a huge deal, the largest performance hit will
//come when you have large arrays/arraylists/hashtables with non-primitive
//type/Comparable objects
private bool ArraysAreEqual( object array1, object array2 )
{
if ( !IsArrayType(array1.GetType()) || !IsArrayType(array2.GetType()) )
return false;
int arrayDimensions = array1.GetType().GetArrayRank();
int array2Dimensions = array2.GetType().GetArrayRank();
if (arrayDimensions != array2Dimensions)
return false;
Array tempArray = array1 as Array;
Array tempArray2 = array2 as Array;
int arrayLength = tempArray.GetLength(0);
for (int c=0; c<arrayLength; c++)
{
Type element1Type = tempArray.GetValue(c).GetType();
Type element2Type = tempArray2.GetValue(c).GetType();
if ( !ValuesAreEqual(tempArray.GetValue(c), tempArray2.GetValue(c)) )
return false;
}
return true;
}
private bool ArrayListsAreEqual( object arrayLst1, object arrayLst2 )
{
if ( !IsArrayList(arrayLst1.GetType()) || !IsArrayList(arrayLst2.GetType()) )
return false;
ArrayList al1 = arrayLst1 as ArrayList;
ArrayList al2 = arrayLst2 as ArrayList;
if ( al1 == null || al2 == null )
{
if ( al1 == null && al2 == null )
return true;
return false;
}
if (al1.Count != al2.Count)
return false;
for ( int c=0; c<al1.Count; c++ )
{
if ( !ValuesAreEqual(al1[c], al2[c]) )
return false;
} //End for loop
return true;
}
private bool HashtablesAreEqual ( object Hashtable1, object Hashtable2 )
{
if ( !IsHashtable(Hashtable1.GetType()) || !IsHashtable(Hashtable2.GetType()) )
return false;
Hashtable ht1 = Hashtable1 as Hashtable;
Hashtable ht2 = Hashtable2 as Hashtable;
if (ht1.Keys.Count != ht2.Keys.Count)
return false;
foreach(object oKey in ht1.Keys)
{
if (!ht2.ContainsKey(oKey))
return false;
if ( !ValuesAreEqual(ht1[oKey], ht2[oKey]) )
return false;
}
return true;
}
#endregion
#region Private Helper Methods
private string GetCompareType(Type t)
{
//Add Code here:
//if ( IsMyType(t) ) return "MYTYPE";
//if ( IsMyType2(t) ) return "MYTYPE2";
if ( IsArrayType(t) ) return "ARRAY";
if ( IsArrayList(t) ) return "ARRAYLIST";
if ( IsHashtable(t) ) return "HASHTABLE";
if ( IsCSharpType(t) ) return "COMPARABLE";
return "";
}
#region Type Checks
//Add Mytype checks
/*
private bool IsMyType(Type t)
{
bool isMyType = false;
if (t.IsSubclassOf(typeof(MyType)) || t.Equals(typeof(MyType)))
isMyType = true;
//Space for any other checks you may have, but
//the above seems to work well enough for me
return isMyType;
}
private bool IsMyType2(Type t)
{
bool isMyType = false;
if (t.IsSubclassOf(typeof(MyType2)) || t.Equals(typeof(MyType2)))
isMyType = true;
//Space for any other checks you may have, but
//the above seems to work well enough for me
return isMyType;
}
//...
*/
private bool IsCSharpType(Type t)
{
//May want to add a check to see if type is inherited from
//IComparable as well.
return (t.IsPrimitive || t.Equals(typeof(string)));
}
private bool IsArrayType(Type t)
{
return t.IsArray;
}
private bool IsArrayList(Type t)
{
return t.Equals(typeof(ArrayList));
}
private bool IsHashtable(Type t)
{
return t.Equals(typeof(Hashtable));
}
#endregion
#endregion
}
}
very simple class and implementation for above
Code:
using System;
namespace MyClasses
{
public class MyType
{
public MyType() {}
#region Used For Equals, ==, != operations
public static bool operator == (MyType mt1, MyType mt2)
{ return mt2.Equals(mt2); }
public static bool operator != (MyType mt1, MyType mt2)
{ return !mt2.Equals(mt2); }
public bool Equals(object obj)
{
//May want to use the HashCode Comparison for
//a faster check
return _Equals.Instance.ValuesAreEqual(this, obj);
}
public override int GetHashCode()
{
//Probably not a great hashing method, but you get the idea
//If you inherited from a parent...
int parentHash = base.GetHashCode();
//Use a list of variables that would make this unique
int childHash = MyString1.GetHashCode();
return parentHash + childHash;
}
#endregion
public string MyString1
{
get { return MyString1; }
set { MyString1 = value as string; }
}
}
}
If anyone has any recommendations/add ons, by all means drop them on here..it is a community forum.
-Kevin
- "The truth hurts, maybe not as much as jumping on a bicycle with no seat, but it hurts.