Can two arrays which contain the same elements not be equal? - c#

I encountered a stunning problem today where I'm trying to find if an object is contained in an List collection. The problem is that the list doesn't find the object and returns index as -1 when I can see it right there already. I then created a custom Index Finder to look for the object by comparing the properties rather than a direct equality where I discovered that one of the object's properties, a ushort array which was identical was returning false when compared, but they contain exactly the same element.
The array is as follows:
{ushort[1]} [0]13
and they're exactly the same in both except that one of the object is contained in a List while the other one is on it's own. What could be the cause of this problem? I've tried all types of different ways to get around the problem but I can't just figure out what the problem is. In this particular case what is causing the comparison between the two arrays to return false, I've tied using Object.equals as well as the normal == comparer. Thanks

For arrays, Equals will return true only if you compare two references that point to the same array. To compare different arrays by content, you can use:
Enumerable.SequenceEqual(a1, a2)
Also, if collection contains objects of your custom type, make sure that these types override Equals, equality operator(==) and GetHashCode.

Related

Default comparer when using OrderBy extension

Out of curiosity: What comparer is used when sorting a bunch of objects using the following extension method?
OrderBy(x=> x)
Background: I have to check wether two ISet< T > instances contain the same elements and considered to use the
bool setsEqual = MySet.SequenceEqual(OtherSet);
method. As the order of those elements contained in the sets are not defined and may differ, a SequenceEqual would fail in those cases where the internal order is not the same. So i would have to explictly define an order. As the order algo for itself is completely irrelevant as long as it´s stable, i just used an "Identity" lambda expression:
bool setsEqual = MySet.OrderBy(x => x).SequenceEqual(OtherSet.OrderBy(x => x);
But what does "Compare the objects themselves" mean to the code? As this OrderBy extension method is a generic one, there must be a default compare algo in place that is able to sort objects without knowing anything more about it, and that would mean a comparison for sorting had to be delegated to the type of the set elements itself. Is there an interface that the elements´ type would have to support, or is there a default comparer (may be comparing internal memory addresses of objects) in place?
To answer the question of sorting: sorting uses IComparable<T> or IComperable if that isn't implemented. The IComperable interfaces force you to implement a int CompareTo(object) method (or int CompareTo(T) method if you used the typed version).
The order of your elements is determined by the sign of the int. The value returned is interpreted as follows:
0: the two objects are equivalent (i.e. the same)
-1: the compared object precedes this object (i.e. comes before this object)
1: the compared object follows this object (i.e. comes after this object)
The actual value is ignored, the sign is all that matters. If you implement your own IComparable interface, you have to choose the semantics for sort order.
Many objects already implement IComparable already, like all your numbers, strings, etc. You'll need to implement it explicitly if you need to sort objects you've created yourself. It's not a bad practice if you intend those objects to be displayed in a list on screen at all.
As to your specific case, where you just need to determine if a set and another IEnumerable are equivalent, then you would use the ISet<T>.SetEquals(IEnumerable<T>) method which is implemented in the standard library set implementations. Sets, by definition, only guarantee the values are unique, so as long as the number of elements are the same, you only need to detect that all the elements in one IEnumerable can be found in the set.
The method used the IComparable<T>-or the IComparable-interface depending on which of both are implemented. If none is implemented the order is arbitrary.
However you won´t need to order you instances before comparing the sets. Simply loop one set and check if all of its elements are contained in the other set. Or use this:
var areEqual = firstSet.All(x => secondSet.Contains(x)) && secondSet.All(x => firstSet.Contains(x));
Or even simpler:
var areEqual = !firstSet.Except(secondSet).Any() && !secondSet.Except(firstSet).Any();
Both ways perform much faster than your appraoch as the iteration of elements stops when the first element is found that does not fit. Using OrderBy you´d loop all elements, regardless if there was already a mismatch.
Unlike for equality, there's no 'default' comparer for objects in general.
It seems that Comparer<TKey>.Default always returns a comparer, for any type TKey. If no sensible comparison method can be determined, you get an exception, but only once the comparer is used.
At least one object must implement IComparable.

CollectionAssert.AreEqual Failing

I am trying to compare two Lists using
CollectionAssert.AreEqual(ListExpected, ListActual);
But I am getting an exception
Expected and actual are both <System.Collections.Generic.List`1[API.Program.Relation]> with 11 elements
Values differ at index [0]
Expected: <API.Program.Relation>
But was: <API.Program.Relation>
But when I compared the zero element using Assert.AreEqual on field by field everything was fine.
Any idea why I cannot compare using CollectionAssert
An object is "declared" equal to another object in .NET is if its Equals(object other) method returns true. You need to implement that method for your API.Program.Relation class, otherwise .NET considers your objects different unless they are reference-equal. The fact that all fields are the same does not matter to .NET: if you need field-by-field equality semantics, you need to provide an implementation of Equals that supports it.
When you override Equals, don't forget to override GetHashCode as well - these must be overriden together.
If you do not want to or cannot override Equals for some reason, you could use an overload of CollectionAssert.AreEqual that takes an instance of IComparer to assist in comparing collection elements.

IStructuralEquatable vs Equals?

according to msdn
IStructuralEquatable
Defines methods to support the comparison of objects for structural
equality. Structural equality means that two objects are equal because
they have equal values. It differs from reference equality, which
indicates that two object references are equal because they reference
the same physical object.
isnt it what Equals should do ? ( when overriding IEquatable) ?
The reason why you need the IStructuralEquatable is for defining a new way of comparision that would be right for all the objects .
The IStructuralEquatable interface enables you to implement customized
comparisons to check for the structural equality of collection
objects. That is, you can create your own definition of structural
equality and specify that this definition be used with a collection
type that accepts the IStructuralEquatable interface.
For example if you want a list that will sort all its elements by a specific definition.
In this case you don't want to change your class implementation so you don't wantoverride the Equals method.
this will define a general way to compare objects in your application.
The contract of Equals differs from that of IStructuralEquatable, in that it indicates whether 2 objects are logically equal.
By default, Equals on a reference type indicates whether two object references reference the same object instance. However, you are able to override Equals according to the logic of your application.
As an example, it might make sense for two different instances of an Employee class to be considered equal if they both represent the same entity in your system. To achieve this, employee objects with matching SSN properties would be treated as logically equal, even if they were not structurally equal.

Why are two empty Lists not Equal?

I thought calling Equals() on two empty Lists would return true, but that's not the case. Could someone explain why?
var lst = new List<Whatever>();
var lst2 = new List<Whatever>();
if(!lst.Equals(lst2))
throw new Exception("seriously?"); // always thrown
Because Equals is checking for references - lst and lst2 are different objects. (note that Equals is inherited from Object and not implemented in List<T>)
You're looking for Linq's SequenceEquals.
Even when using SequenceEquals, don't expect it to work with your Whatever class on non-empty lists (unless it is a struct). You may want to implement a comparer, and use the right overload.
Equals here is comparing reference of two lists which would be different because they are separate lists and that's why it will always be false in this case.
Object documentation (MSDN documentation):
The default implementation of Equals supports reference equality for reference types, and bitwise equality for value types. Reference equality means the object references that are compared refer to the same object. Bitwise equality means the objects that are compared have the same binary representation.
List documentation (MSDN documentation):
Determines whether the specified Object is equal to the current Object. (Inherited from Object.)
You have two different objects (two times new ...) so there not the same.
Because it compares on object identity, not the contents of the list. They are two separate objects.
See this answer from the C# FAQ.
The Equals implementation of List<T> is the inherited one from Object:
The default implementation of Equals supports reference equality for reference types
In other words, since these are two different lists, they have different references, so Equals returns false.
List<T>.Equals() will compare the references of the two lists and return true if they are equal. If you want to compare the elements of two lists, use List<T>.SequenceEquals()
When you compare 2 lists with each other, the equals method will NOT compare the items that are in that list. It will just compare the List object with the other List object. these have their own 'identity'.
They are two different lists allocated somewhere in memory (with new keyword). Therefore they cannot be equal. If you want such functionality you should build your own object inheriting from List and overriding Equals function
In C# and .Net you have reference types and value types.
Value types represent, well, values. integer, double, DateTime and so on.
When you compare value types you compare their actual value, so:
int a = 10;
int b = 10;
if( a == b )
{
// this will fire
}
Note that each variable refers to a new copy, so:
int c = a;
c = c+5;
if( a == c )
{
// this won't, because a==10 and c==15
}
Reference types are objects that you pass around a do things with. You can have more than one variable referring to the the same object, so:
var a = new List<Whatever>();
var b = new List<Whatever>();
if( a == b )
{
// this won't fire, a and be are separate objects
}
var c = a;
c.Add(new Whatever());
if( a == c )
{
// this will, a and c are the same object.
a[0]; // holds the value added to c
}
Finally some special cases of reference types behave like value types, for instance string.
As far as I can see from the documentation .Equals on List is the inherited method from Object which means it checks if the lists are the same object. Since you have made two object they will not be the same.
Two different things cant be the same, even if these things got the same items (or are both empty).
You dont need to be good at programing to understand this ;) Lets say you have a this and that, its not important whats inside this and that. Its just important that a this is not a that or a that is not a this. Thats what you you check there with equals

C# how to access array info unknown type within object

I have an object called SampleObject that holds an array of strings called StringArray. In order for me to access the first element in that array I need to write:
((string[])(SampleObject))[0]
However if I were to not know the type of the array how would I be able to approach this?
((SampleObject.GetType())(SampleObject))[0];
I tried something like this but it expects a method name.
Thanks.
You can use Array.GetValue - all array types are derived from Array, whatever the element type is. You may need to think carefully about rectangular arrays though, and arrays with a non-zero lower bound.
While Jon's answer is correct, you can abuse array co-variance, provided you have a normal (one dimensional, starting at 0) array of reference type.
return ((object[])SampleObject)[3];
Return the 3rd element in the array. You can also cast it to a non-generic IList if it not only will change the element type, but possibly the container itself.
If they are going to be based on c# object class, you can use GetType() - this will return a System.Type (see http://msdn.microsoft.com/en-us/library/system.object.gettype.aspx). Otherwise you could base them off your own base object that has a type define for all possible values.
Another approach would be to use Reflection to determine the type and to manipulate the data. While this is applicable on all types of objects (not only arrays), for the scenario you described I would go with the solution of Jon Skeet.

Categories

Resources