Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing structs in a generic method

Tags:

c#

generics

Here's a simplified case of what I'm struggling with:

public bool CompareStruct<S>(S a, S b) where S : struct
{
  return a == b;
}

The above will not compile with the error Operator '==' cannot be applied to operands of type 'S' and 'S'.

Normally, I wouldn't be surprised. But I've indicated that S is a struct - so why can't I compare the two parameters?

I don't think this SO question has any relevancy here - after all, I'm working with struct types, not reference types.

like image 903
Shaamaan Avatar asked Jun 29 '17 10:06

Shaamaan


Video Answer


3 Answers

The problem here is that the default behavior of == in C# is reference equality. Reference equality in structs makes no sense because it will always return false.

The compiler has no way of knowing if == has been overloaded and S has value equality semantics and therefore disallows its use.

To get around this, use Equals and consider constraining S to IEquatable<S> if appropiate to avoid unnecessary boxing operations.

like image 181
InBetween Avatar answered Oct 05 '22 07:10

InBetween


The problem is that when you specify the constraint that the generic type parameter is struct i.e. ValueType, it is not necessary that the struct which calls this method has provided the overload implementation for == and != operator for it, as for custom value types, when we define it we need to provide the == and != operator overloads for them to be used.

An alternate can be to use Object.Equals method or call the Equals() method on it's own instance like:

public bool CompareStruct<S>(S a, S b) where S : struct
{
  return a.Equals(b);
}

or:

public bool CompareStruct<S>(S a, S b) where S : struct
{
  return Object.Equals(a,b);
}

The point to remember is that but the equality operator is by default not available for value types unless you overload the == operator for that type and for reference types using == operator does is checking for reference equality so that's why applying constraint to class works fine.

I once wrote a post about this which might be helpful which can be read at this link (Equality Operator (==) and Value Types in C#)

like image 25
Ehsan Sajjad Avatar answered Oct 05 '22 08:10

Ehsan Sajjad


You can't use == on user-defined ValueTypes unless you explicitly override the == and != operators. This is because the default implementation for a struct doesn't implement these operators. For instance, the below doesn't compile:

struct Foo
{

}

void Main()
{
    Foo f1;
    Foo f2;

    if(f1 == f2) // The compiler complains here
    {

    }
}

So if you can't do that for known structs (by default), then you can't do that for generic structs (less information known at compile time) unless you provide more information (for example that this struct have to implement IEquatable<S>)

The above would work for classes because they uses reference equality by default when using ==. That doesn't apply to Value Types because they are copied by value.

like image 21
Zein Makki Avatar answered Oct 05 '22 07:10

Zein Makki