Saturday, May 10, 2008

Extension Methods C# .NET 3.5

Extension Methods are new at .NET 3.5 It let you add methods to existent class.

Example:

public static class Extensions
{
public static int ToInt32Ext(this string s) // we add the this word
{
return Int32.Parse(s);
}

public static int ToInt32(string s)
{
return Int32.Parse(s);
}

}

void Main()
{
string s = "5";
int x = s.ToInt32Ext(); // using the extension method
Console.WriteLine(x);
x = Extensions.ToInt32(s);
Console.WriteLine(x);
}

Please notice:
  • The this word must be the first argument in the method,in this example we only have one argument but if you have more remember that it must be the first thing.
  • The class must be a static class.
I think it is a nice feature but doesn't really add new power to the language.



Friday, May 9, 2008

Equals and GetHashCode The Right Way!!!!!

Hi
Recently I witness many mistakes when creating new class. many developers override Object.GetHashCode() in a wrong way!!! that can make error that will be very hard to find. Lets start with the basic rules when writing your own GetHashCode:
  • If X.Eqauls(Y) == true then X.GetHashCode() == Y.GetHashCode(). if two objects are equals they must have the same HashCode.
  • If X.GetHashCode() != Y.GetHashCode() then X.Equals(Y) == false. If two objects has defraent hash code they cant be Equal to each other.
  • object GetHashCode() must NOT be changed during it life cycle. Once the object was created it hash code must NOT change!!!
  • If X.Eqauls(Y) == false then X.GetHashCode() Should (NOT A MUST) be defrant from Y.GetHashCode()
If you creates your own object and overrides Equals you will get an Warning:
Here is an example of a wrong way to make HashCode and what will happen:

class
MyWrongObject
    {
private int m_One;
public int One
{
get { return m_One; }
set { m_One = value; }
}
public MyWrongObject() { }
public MyWrongObject(int one)
{
m_One = one;
}

public override bool Equals(object obj)
{
MyWrongObject other = obj as MyWrongObject;
if (other != null)
return (One == other.One);
else
return false;
}

public override string ToString()
{
return String.Format("MyWrongObject[{0}]", One);
}

public override int GetHashCode()
{
return ToString().GetHashCode();
}


public static void Main(string[] args)
{
HashSet<MyWrongObject> set1 = new HashSet<MyWrongObject>();
MyWrongObject obj1 = new MyWrongObject(1, 1);
set1.Add(obj1);
if (set1.Contains(obj1))
Console.WriteLine("Found obj1");
obj1.One = 2; // This line changes the GetHashCode() of obj1
if (set1.Contains(obj1))
{
// We wont see this line because Contains looks at the GetHashCode()
then at Equals()

Console.WriteLine("You won't see this line");
}
else
Console.WriteLine("Hmmm.. can't find obj1 but obj1 is here");
foreach (MyWrongObject obj in set1)
{
if (obj1.Equals(obj))
Console.WriteLine("obj:{0} Can't find obj1 but obj1 is here", obj);
}
}
}



Please notice that you can't make a setter to a member that changes the GetHashCode() of the object.
If you do that you should think about throwing an exeption when using GetHashCode()

Enjoy,