5

I have read the following statement regarding to the comparison of C# value types in C# in Depth, Second Edition several times.

page 77,

When a type parameter is unconstrained (no constraints are applied to it), you can use == and != operators, but only to compare a value of that type with null. You can’t compare two values of type T with each other.

...

When a type parameter is constrained to be a value type, == and != can’t be used with it at all.

If I understand (I don't think so) it correctly, it basically tells me that you cannot use == or != to compare two value types. Why why why?

It will be better if a simple example can be given for this case. Can someone give me a little idea what the above paragraph tries to convey?

Community
  • 1
  • 1
q0987
  • 34,938
  • 69
  • 242
  • 387
  • 2
    I suspect this is to avoid confusion with operator overloading, since an overloaded == operator would not be used when the generic type parameter is a value type. You can use Object.Equals, however, which well-behaved value types will implement and which will have the same behavior as == (for well-behaved types). – Dan Bryant Jun 03 '11 at 02:51
  • 1
    @Dan Bryant, it's not only to avoid confusion. There's no guarantee that a value type supports the == and != operators, and we *can't use the System.Object implementation for value types, because testing reference equality only works on boxed instances.* Well, we could in theory specify that the operands be boxed in order to use the reference equality check, but then the expression would always be false, which is clearly useless. – phoog Jun 03 '11 at 03:13
  • @phoog, the static `Object.Equals` will actually call the Equals implementation of the Object (even if it's a boxed value type), so it's a valid way to compare even value types. It also handles comparison of null with value types. `Object.ReferenceEquals` explicitly forces the check to be for reference equality, which can be helpful in cases where a reference type overrides the equality operator, but has a bug for the null comparison case (I've encountered this before with a third-party API.) – Dan Bryant Jun 07 '11 at 16:06
  • @Dan Bryant, yes, static (and also instance) object.Equals will do what you describe. The problem is that the == operator does not do this, and therefore it's impossible to meaningfully apply that operator in the case where a generic type parameter is a value type. – phoog Jun 08 '11 at 03:34

2 Answers2

7

It simply means this when constraining to a value type (second paragraph)

static bool TryToCompare<T>(T first, T second) where T : struct
{
    return first == second; // not legal
    return first.Equals(second); // legal
}

Without the value-type constraint on the generic, it also says this (first paragraph)

static bool TryToCompare<T>(T first, T second) 
{
    return first == second; // not legal
    return first == null; // legal
    return first.Equals(second); // legal
}

If you constrain T to a reference type, you can get away with using ==

static bool TryToCompare<T>(T first, T second) where T : class
{
    return first == second; // legal
    return first == null; // legal
    return first.Equals(second); // legal
}
Anthony Pegram
  • 123,721
  • 27
  • 225
  • 246
  • the first example on your second function fails b/c we don't have any constraint on T and T may be struct or class. Is that correct? -thx – q0987 Jun 03 '11 at 03:00
  • 1
    More or less. There is no guarantee a value type `T` defines the `==` operator. For more on this topic, I would suggest you see this question and the top answer: http://stackoverflow.com/questions/5808057/operator-cant-be-applied-to-type-t – Anthony Pegram Jun 03 '11 at 03:06
  • +1: basically I only use `==` and `!=` against constants. If I'm not mistaken, you can also use `default(T)` for evaluation. Otherwise, I use `Equals()`. – IAbstract Jun 03 '11 at 03:10
0

Objects aren't comparable because a comparison using == is testing whether the reference is the same (the memory address). You would normally use if (string1.Equals(string2)).

Something I don't understand is that I have seen circumstances where == works with strings, and circumstances where it doesn't.

peter
  • 13,009
  • 22
  • 82
  • 142
  • From a results POV, `==` and `string1.Equals(string2)` shouldn't be any different. They're calculated in different ways, but for short strings, `Equals` has a slight speed advantage. Good article here: http://www.dotnetperls.com/string-equals – keyboardP Jun 03 '11 at 03:01
  • On strings, you start to see "unexpected" results when comparisons are made against string *as* objects. Consider `string x = "ONE"; string y = string.Format("ON{0}", "E"); bool b = x == y; bool c = (object)x == (object)y;` `b` will be true, `c` will be false. However, change `y` to be `string y = "ONE";`, and now `c` will also be true. – Anthony Pegram Jun 03 '11 at 03:17
  • If the reference to either string operand has a compile-time type of object, then == will compile to a reference equality check. If they are both string-type references, you'll get the string implementation of the operator. – phoog Jun 03 '11 at 03:21