Compare objects based on IComparable<T> with unknown T

J

JV

I need to implement a method that processes two objects. Among other things,
the method may want to try to compare the two objects, which should use the
CompareTo method, provided the two objects are the same class and the class
implements IComparable<T>.

void process(object o1, object o2)
{
if (o1.GetType().Equals(o2.GetType()))
{
Type t = o1.GetType();

if t implements IComparable<T> where T is not known then ???
compare o1 and o2 using their CompareTo method ???
}
}

I specifically do not want the objects to implement the non-generic
IComparable version.

How can I check the type if it implements IComparable<T> and if so, how
could I then call the CompareTo method?
 
A

Adam Clauss

JV said:
I need to implement a method that processes two objects. Among other things,
the method may want to try to compare the two objects, which should use the
CompareTo method, provided the two objects are the same class and the class
implements IComparable<T>.

void process(object o1, object o2)
{
if (o1.GetType().Equals(o2.GetType()))
{
Type t = o1.GetType();

if t implements IComparable<T> where T is not known then ???
compare o1 and o2 using their CompareTo method ???
}
}

I specifically do not want the objects to implement the non-generic
IComparable version.

How can I check the type if it implements IComparable<T> and if so, how
could I then call the CompareTo method?
Hmm, I think calling into the generic interface, without knowing type T
as your method is currently written would require a use of reflection to
invoke the CompareTo method. However, could you make the method itself
generic?

(Disclaimer: code written freehand, may contain typos):
void process<T>(T o1, T o2) where T : IComparable<T>
{
if (o1 != null && o2 != null)
{
int compareVal = o1.CompareTo(o2);
// Do whatever you want with the comparison here
}
}
 
J

JV

Adam Clauss said:
Hmm, I think calling into the generic interface, without knowing type T
as your method is currently written would require a use of reflection to
invoke the CompareTo method. However, could you make the method itself
generic?
No, unfortunately, the process method is supposed to be universal and is
part of a library that should work with any provided type. The only
expectation is that the process method should make use of special comparators
is the objects provide them.

Other languates (such as Java) would permit a wildcard, e.g.

((IComparable<?>)o1 ). CompareTo( o2 )

I haven't found anything like that in C#. Am I missing something?
 
A

Adam Clauss

JV said:
No, unfortunately, the process method is supposed to be universal and is
part of a library that should work with any provided type. The only
expectation is that the process method should make use of special comparators
is the objects provide them.

Other languates (such as Java) would permit a wildcard, e.g.

((IComparable<?>)o1 ). CompareTo( o2 )

I haven't found anything like that in C#. Am I missing something?

If your method needs to handle all types, you could certainly remove the
IComparable<T> restriction:

void process<T>(T o1, T o2)
{
IComparable<T> comp1, comp2;
comp1 = o1 as IComparable<T>; // returns null if the specified object
does not cast to IComparable<T>
comp2 = o2 as IComparable<T>;
if (comp1 != null && comp2 != null)
{
int compareVal = comp1.CompareTo(comp2);
// Do whatever you want with the comparison here
}
else
{
// Do whatever you want when they do not implement IComparable<T>
}
}
 
A

Adam Clauss

Adam said:
If your method needs to handle all types, you could certainly remove
the IComparable<T> restriction:

void process<T>(T o1, T o2)
{
IComparable<T> comp1, comp2;
comp1 = o1 as IComparable<T>; // returns null if the specified
object does not cast to IComparable<T>
comp2 = o2 as IComparable<T>; if (comp1 != null && comp2 != null)
{
int compareVal = comp1.CompareTo(comp2);
// Do whatever you want with the comparison here
}
else
{
// Do whatever you want when they do not implement IComparable<T>
}
}

That CompareTo line should now read:
int compareVal = comp1.CompareTo(o2);

And you could probably toss out the comp2 object altogether. Figures, I
didn't put my code disclaimer this time!

-Adam
 
P

Peter Duniho

JV said:
No, unfortunately, the process method is supposed to be universal and is
part of a library that should work with any provided type. The only
expectation is that the process method should make use of special comparators
is the objects provide them.

Other languates (such as Java) would permit a wildcard, e.g.

((IComparable<?>)o1 ). CompareTo( o2 )

Java only permits that because "IComparable<?>" is equivalent to
"IComparable", due to type erasure. Note also that while your original
post says "how can I check the type if it implements IComparable<T>",
the Java code you posted makes no such check. It just assumes that
IComparable is implemented.
I haven't found anything like that in C#. Am I missing something?

C# generics are reified. That is, the generic type argument is actually
compiled into the actual code. So in C#, to cast to a generic type, you
actually need to know what to use for the type parameter.

But, any type that implements IComparable<T> is almost always going to
implement IComparable. So you can just use IComparable in its place.

I don't really understand the question, because your first post says you
don't want objects to implement IComparable, but you apparently do want
them to implement IComparable<T>.

If you _only_ want to deal with objects that implement IComparable<T>, I
don't understand the requirement, but Adam's replies should work very
well. Like he said, you can either make the method generic, and then
use the "as" operator to test for the implementation (this is similar to
doing "instanceOf()" and a cast in Java, all rolled into a single
operator). If the method cannot be generic, then you will have to use
reflection. Note that reflection is going to be MUCH slower than generics.

Personally, I would revisit your requirement that you must work with
IComparable<T> and not IComparable. Especially if you cannot make the
method generic. It should be very unusual for code to implement
IComparable<T> without implementing IComparable, since the latter is
trivial to implement given the former.

Pete
 

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