Using IComparer <T> .Compare (T, T) in C #
I'm trying to create a generic priority queue but int EnQueue, but I still can't seem to deal with the errors that I get using IComparer.
Error: Error 1 An object reference is required for a non-static field, method, or property. System.Collections.Generic.IComparer.Compare (T, T) '
public void inQ(T dat)//adding element in place, increasing order
{
if (start == null)//that means that the RPQ is empty
{
start = new node(dat);
return;
}
if (IComparer<T>.Compare(start.data, dat) > 0)//Doesn't work
{
start = new node(dat, start);
return;
}
//Default Case
//no need for an else, actually
node q = start;
while (q.next != null && Comparer<T>.Default.Compare(q.next.data, dat) < 0)//Works Perfectly
q++;
q.next = new node(dat, q.next);
}
source to share
What happened
you need an instance IComparer<T>
to be able to call a method Compare
on it ... remember that this is an interface, it has no static methods.
This is why it doesn't work:
IComparer<T>.Compare(start.data, dat) > 0
On the other hand, Comparer<T>
is a class and offers you a static property Default
that gives you an instance IComparer<T>
...
This is why it works:
Comparer<T>.Default.Compare(q.next.data, dat) < 0
Getting an instance IComparer<T>
You might consider storing the field with your instance IComparer<T>
and using that. This will minimize confusion and also allow you to get IComparer<T>
in the constructor to be stored in that field - which is useful if the client wants to create custom behavior.
Default instance
If you want to use the default matcher, you can get it from it:
var comparer = Comparer<T>.Default;
This comparator will give the default behavior for whatever is used T
. This behavior is equivalent to being called CompareTo
on instances T
with additional handling for zeros. Since you cannot use the method CompareTo
when your int is is null, you can check for null before calling CompareTo
... using a matcher fixes the problem.
Implementation IComparer<T>
Since it IComparer<T>
is an interface, you can write a class to implement it, this class must have a method Compare
with whatever logic you want. Then you instantiate this class and use it wherever the system wants IComparer<T>
.
See implementation example IComparer<T>
on MSDN
// This class is not demonstrated in the Main method
// and is provided only to show how to implement
// the interface. It is recommended to derive
// from Comparer<T> instead of implementing IComparer<T>.
public class BoxComp : IComparer<Box>
{
// Compares by Height, Length, and Width.
public int Compare(Box x, Box y)
{
if (x.Height.CompareTo(y.Height) != 0)
{
return x.Height.CompareTo(y.Height);
}
else if (x.Length.CompareTo(y.Length) != 0)
{
return x.Length.CompareTo(y.Length);
}
else if (x.Width.CompareTo(y.Width) != 0)
{
return x.Width.CompareTo(y.Width);
}
else
{
return 0;
}
}
}
Your comparator will be an instance of the class:
var comparer = new BoxComp();
Note : the documentation actually suggests inheriting from Comparer<T>
instead of direct IComparer<T>
, the pragmatic reason is that it Comparer<T>
also implements IComparer
in addition to IComparer<T>
.
Create IComparer<T>
with a delegate
If you are not familiar with what a delegate is, let's say it is a method reference, so you can have a variable that references a method and passes it.
You can create IComparer<T>
if you have a method delegate that does the comparison ... this is done by calling the method the Comparer<T>.Create
witch will take the delegate to the desired method. For example, you can use lambda expresion like this:
var comparer = Comparer<string>.Create
(
(str1, str2) => str1.Length.CompareTo(str2.Length)
);
The above code is shorthand for this:
Comparison<string> comparison = (str1, str2) => str1.Length.CompareTo(str2.Length);
var comparer = Comparer<string>.Create(comparison);
This, in turn, is shorthand for this:
Comparison<string> comparison = delegate(string str1, string str2)
{
return str1.Length.CompareTo(str2.Length);
};
var comparer = Comparer<string>.Create(comparison);
What is sugar for something like this (except that in the above code, the method is anonymous):
Comparison<string> comparison = StringComparison;
var comparer = Comparer<string>.Create(comparison);
// ...
private static int StringComparison(string str1, string str2)
{
return str1.Length.CompareTo(str2.Length);
}
Additional indications :
source to share