Generics and comparison (follow on from my previous "Generics and collections" thread)

M

Martin Robins

Marc has sorted my problem with the collections, however I am now in a new scenario; I am trying to compare a generic property value before setting it as shown below ...

public T Value {
get { return this.value; }
set {
if ( this.value != value ) {
this.value = value;
this.OnValueChanged(EventArgs.Empty);
}
}
}

This code produces the Operator '==' cannot be applied to operands of type 'T' and 'T' error at compile time!
I am sure that I am not the only person to have tried this, any clues as to the correct work around?

I have tried restricting 'T' to IComparable in a where clause and then casting 'this.value' and 'value' to IComparable for the comparison - the code then compiles but is this the right answer? It feels wrong, but I am quickly learning that my own understanding of generics is much lower than I thought it was!

Thanks in advance.
 
R

Rudy Velthuis

Martin said:
Marc has sorted my problem with the collections, however I am now in
a new scenario; I am trying to compare a generic property value
before setting it as shown below ...

public T Value {
get { return this.value; }
set {
if ( this.value != value ) {
this.value = value;
this.OnValueChanged(EventArgs.Empty);
}
}
}

This code produces the Operator '==' cannot be applied to operands of
type 'T' and 'T' error at compile time!

You'll have to put a constraint on T (where clause), so that it only
applies to instances that implement IEquitable<T>, and then use
IEquitable<T>.Equals() to check for equality.

You can also, somehow, omit the constraint and provide the class an
instance of IComparer or IEqualityComparer, to do the work for you.
That has advantages, but also disadvantages.
 
M

Martin Robins

Though it compiles, the original IComparable idea did not work; the comparisons would often return incorrect results.

I have resolved it for now using "if ( this.value == null ? value != null : !this.value.Equals(value) )" but I am still open to a better way if it exists ...

Martin.

"Martin Robins" <martin at orpheus-solutions dot co dot uk> wrote in message Marc has sorted my problem with the collections, however I am now in a new scenario; I am trying to compare a generic property value before setting it as shown below ...

public T Value {
get { return this.value; }
set {
if ( this.value != value ) {
this.value = value;
this.OnValueChanged(EventArgs.Empty);
}
}
}

This code produces the Operator '==' cannot be applied to operands of type 'T' and 'T' error at compile time!
I am sure that I am not the only person to have tried this, any clues as to the correct work around?

I have tried restricting 'T' to IComparable in a where clause and then casting 'this.value' and 'value' to IComparable for the comparison - the code then compiles but is this the right answer? It feels wrong, but I am quickly learning that my own understanding of generics is much lower than I thought it was!

Thanks in advance.
 
M

Martin Robins

Rudy,

Interesting interface (IEquatable); not seen that one before.
Will let you know if this works for me.

Thanks.
 
R

Rudy Velthuis

Martin said:
Though it compiles, the original IComparable idea did not work; the
comparisons would often return incorrect results.

That is a problem with the implementation of the interface for that
particular instantiation of T, then. If it were correctly implemented,
that should not happen.
 
B

Barry Kelly

Martin Robins said:
Marc has sorted my problem with the collections, however I am now
in a new scenario; I am trying to compare a generic property value
before setting it as shown below ...

public T Value {
get { return this.value; }
set {
if ( this.value != value ) {
this.value = value;
this.OnValueChanged(EventArgs.Empty);
}
}
}

This code produces the Operator '==' cannot be applied to operands of type
'T' and 'T' error at compile time!
I am sure that I am not the only person to have tried this, any clues as
to the correct work around?

The normal pattern for comparing values of a generic type is to use
Comparer<T>.Default (if you need ordering) or
EqualityComparer<T>.Default (if you need equality and hashing).

EqualityComparer<T>.Default delegates to an IEquatable<T> interface if
it exists, or fall back to the Object.Equals override, if any.

Then, if you deal with some T where you want to customize behaviour
(strings come to mind - do you want case-sensitive versus insensitive
behaviour?), you create an overloaded constructor which takes an
IEqualityComparer<T> instance, and pass EqualityComparer<T>.Default in
the other overload. All comparisons should be done through the cached
interface value.

For the concrete case of strings, you can then use
StringComparer.Ordinal, StringComparer.InvariantCultureIgnoreCase, as
the argument etc.

-- Barry
 
M

Martin Robins

Barry,

Thanks; that seems to have done the trick (in as much as it is providing the
correct results).

Martin.
 
M

Martin Robins

Barry,

My last message sounded really bad; sorry! Your suggestions have provided
the answer I was looking for. I particularly liked the IEqualityComparer
suggestion and this (along with the overriden constructor) is the one that I
am going with.

Martin.
 

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