Generic Class example and how to use Generic Classes (format)

R

raylopez99

Here is an example of a home grown generic class, representing a pair
of values. Adapted from Jon Skeet's book "C# In Depth".

The generic class is "sealed" for some reason (I think for
performance) so you cannot derive from it, but that's optional. The
main thing in this example is to show the right format for using these
generic classes, which was not present in the code snippet in Skeet's
book.

Does anybody know why the .Equals does not work below? See //DOES NOT
WORK--WHY? below
I suspect it's because the equals is only compairing the shallow copy
or references (see the hash code)

RL

(C) 2008 by Ray Lopez, all world rights reserved

// Generics – from p. 84 of Jon Skeet C# in Depth
// OUTPUT (works as expected)
101 is: 101
string is: Generics1.Class1, while myClass1Pair.First.i is: 101
myC 2: Generics1.Class1
myClassTwo2.myClass1Pair.First.i: 123
myClassTwo2.myClass1Pair.Second.i: 321
myClassTwo2.myClass1Pair.First.j: 321
myClassTwo2.myClass1Pair.Second.j: 123
myCl2 != myClassTwo2
hash's are: 58225482, 54267293 //note: hash's are different so objects
not 'equal'

Press any key to continue . . .

//////////////////

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Generics1
{
class Program
{
static void Main(string[] args)
{
Class1 myCl1 = new Class1();
Class2 myCl2 = new Class2();

Console.WriteLine("101 is: {0}", myCl1.i);
string s= myCl2.myClass1Pair.First.ToString();
int j1 = myCl2.myClass1Pair.First.i;
Console.WriteLine("string is: {0}, while
myClass1Pair.First.i is: {1}", s,j1);

Class2 myClassTwo2 = new Class2(11.11, 123, 321);
string s2 = myClassTwo2.myClass1Pair.First.ToString();
Console.WriteLine("myC 2: {0}", s2);
int j2 = myClassTwo2.myClass1Pair.First.i;
Console.WriteLine("myClassTwo2.myClass1Pair.First.i: {0}",
j2);
int j3 = myClassTwo2.myClass1Pair.Second.i;
Console.WriteLine("myClassTwo2.myClass1Pair.Second.i: {0}",
j3);
int j4 = myClassTwo2.myClass1Pair.First.j;
Console.WriteLine("myClassTwo2.myClass1Pair.First.j: {0}",
j4);
int j5 = myClassTwo2.myClass1Pair.Second.j;
Console.WriteLine("myClassTwo2.myClass1Pair.Second.j: {0}",
j5);
if (myCl2 != myClassTwo2) Console.WriteLine("myCl2 !=
myClassTwo2");
Class2 myClassTwo22 = new Class2(11.11, 123, 321);

if ((myClassTwo2.Equals(myClassTwo22)))
Console.WriteLine("(myClassTwo2 == myClassTwo22)");
// above DOES NOT WORK--WHY? Because different references
pointed to, even though contents equal

int HashCode01 = myClassTwo2.GetHashCode();
int HashCode02 = myClassTwo22.GetHashCode();
Console.WriteLine("hash's are: {0}, {1}", HashCode01,
HashCode02);

}
}
}
///////////////////////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Generics1
{
class Class1
{
public int i;
public int j;
Pair<int, int> myPair;

public Class1()
{
myPair = new Pair<int, int>(10,10);
i = 101;
j = 0;
}
public Class1(int i, int j)
{
this.i = i; this.j = j;
}
}
class Class2
{
public double d;
public Pair<Class1, Class1> myClass1Pair;
public Class2()
{
d = 10.0;
myClass1Pair = new Pair<Class1, Class1>(new Class1(), new
Class1());
}
public Class2(double d, int Class1Int01, int Class1Int02)
{
this.d = d;
myClass1Pair = new Pair<Class1, Class1>(new
Class1(Class1Int01, Class1Int02), new Class1(Class1Int02,
Class1Int01));
}
}

////////// THe below is from Jon Skeet's book ////////////

public sealed class Pair<TFirst, TSecond>
: IEquatable<Pair<TFirst, TSecond>>
{
private readonly TFirst first;
private readonly TSecond second;
public Pair(TFirst first, TSecond second)
{
this.first = first;
this.second = second;
}
public TFirst First
{
get { return first; }
}
public TSecond Second
{
get { return second; }
}
public bool Equals(Pair<TFirst, TSecond> other)
{
if (other == null)
{
return false;
}
return EqualityComparer<TFirst>.Default
..Equals(this.First, other.First) &&
EqualityComparer<TSecond>.Default
..Equals(this.Second, other.Second);
}
public override bool Equals(object o)
{
return Equals(o as Pair<TFirst, TSecond>);
}
public override int GetHashCode()
{
return EqualityComparer<TFirst>.Default
..GetHashCode(first) * 37 +
EqualityComparer<TSecond>.Default
..GetHashCode(second);
}
}

}
//////////////////////
 
J

Jon Skeet [C# MVP]

Here is an example of a home grown generic class, representing a pair
of values.  Adapted from Jon Skeet's book "C# In Depth".

The generic class is "sealed" for some reason (I think for
performance) so you cannot derive from it, but that's optional.

The class is immutable, and immutable types are generally sealed. In
addition, I'm a fan of the idea of sealing any class which isn't
designed specifically to be derived from.
 The main thing in this example is to show the right format for using these
generic classes, which was not present in the code snippet in Skeet's
book.

Except you've only shown examples where TFirst = TSecond, rather than
Does anybody know why the .Equals does not work below?  See //DOES NOT
WORK--WHY? below
I suspect it's because the equals is only compairing the shallow copy
or references (see the hash code)

No, it's comparing them with the default equality comparer, which will
use Equals/GetHashCode where appropriate. You haven't overridden
either Equals or GetHashCode in Class1 or Class2, so you end up
getting identity comparisons. Override those methods appropriately and
all will be well.

Jon
 

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