Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Just a starting point for comparing

Status
Not open for further replies.

kmfna

MIS
Sep 26, 2003
306
0
0
US
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
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.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top