Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is Array.IndexOf not checking for IEquatable like List<T> does?

Consider this code:

public static void Main()
{
    var item = new Item { Id = 1 };

    IList list = new List<Item> { item };
    IList array = new[] { item };

    var newItem = new Item { Id = 1 };

    var lIndex = list.IndexOf(newItem);
    var aIndex = array.IndexOf(newItem);

    Console.WriteLine(lIndex);
    Console.WriteLine(aIndex);
}

public class Item : IEquatable<Item>
{
    public int Id { get; set; }

    public bool Equals(Item other) => other != null && other.Id == Id;

}

Results:

0
-1

Why are the results different between List<T> and Array? I guess this is by design, but why?

Looking at the code of List<T>.IndexOf makes me wonder even more, since it's porting to Array.IndexOf.

like image 816
Shimmy Weitzhandler Avatar asked Jul 09 '17 02:07

Shimmy Weitzhandler


People also ask

Why can't I use iequatable in an array?

An Array knows nothing about <T> so it can't implement or use the IEquatable interface. An Array instead holds objects that are not generic. It will call Equals to compare one object to another as all objects have an Equals method which you are free to override.

How do you know if an element exists in an array?

Therefore, if .indexOf () returns a number greater than or equal to zero (or in comparator terms: >= 0 ), then we know that the element we're looking for exists in the array. Note: This example is meant to be friendly and familiar even to new developers, but Using .indexOf () to identify "collisions" within an array is something of a blunt tool.

Why doesn't array<t> support equality testing for generic object collections?

Because generic object collections use the IEquatable<T> interface when testing for equality in such methods as Contains, IndexOf, LastIndexOf, and Remove. An Array knows nothing about <T> so it can't implement or use the IEquatable interface.

Why does indexOf () return-1 when searching for a string?

This is because the string 'c' is in the third position, and arrays (like just about everything else in programming) use a zero-based index - meaning that 'a' is in position 0, 'b' is in position 1, 'c' is in position 2, and so on. However, if what you're looking for is not found in the array, .indexOf () will return -1.


1 Answers

Implementation of IndexOf in array class calls method:

public static int IndexOf(Array array, object value, int startIndex, int count)

As you see, it uses object as value parameter. In this method there is code:

object obj = objArray[index];
if (obj != null && obj.Equals(value))
    return index;

Classs works with objects, so it calls public virtual bool Equals(object obj) method, not generic one.

In List class IndexOf uses generic implementation:

public static int IndexOf<T>(T[] array, T value, int startIndex, int count)

So, it uses generic quality comparer:

EqualityComparer<T>.Default.IndexOf(array, value, startIndex, count);

UPD: I wrote a little post about this problem: http://blog.rogatnev.net/2017/07/14/IndexOf-with-IEquatable.html

like image 92
Backs Avatar answered Sep 22 '22 21:09

Backs