T []。包含结构和类不同的行为 [英] T[].Contains for struct and class behaving differently

查看:217
本文介绍了T []。包含结构和类不同的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是这是一个后续问题:
<一href=\"http://stackoverflow.com/questions/19887562/why-is-listt-contains-and-t-contains-behaving-differently\">List<T>.Contains和T []。含有不同的行为

This is a followup question to this: List<T>.Contains and T[].Contains behaving differently

T []包含行为是不同的,当 T 是类和结构。假设我有这样的结构

T[].Contains is behaving differently when T is class and struct. Suppose I have this struct:

public struct Animal : IEquatable<Animal>
{
    public string Name { get; set; }

    public bool Equals(Animal other) //<- he is the man
    {
        return Name == other.Name;
    }
    public override bool Equals(object obj)
    {
        return Equals((Animal)obj);
    }
    public override int GetHashCode()
    {
        return Name == null ? 0 : Name.GetHashCode();
    }
}

var animals = new[] { new Animal { Name = "Fred" } };

animals.Contains(new Animal { Name = "Fred" }); // calls Equals(Animal)

在这里,通用等于 的是正确如我所料调用。

Here, generic Equals is rightly called as I expected.

但在类的情况下

public class Animal : IEquatable<Animal>
{
    public string Name { get; set; }

    public bool Equals(Animal other)
    {
        return Name == other.Name;
    }
    public override bool Equals(object obj) //<- he is the man
    {
        return Equals((Animal)obj);
    }
    public override int GetHashCode()
    {
        return Name == null ? 0 : Name.GetHashCode();
    }
}

var animals = new[] { new Animal { Name = "Fred" } };

animals.Contains(new Animal { Name = "Fred" }); // calls Equals(object)

非普通等于 的叫,带走落实`IEquatable的好处。

The non generic Equals is called, taking away the benefit of implementing `IEquatable.

为什么数组调用等于不同的结构[] 类[] 即使两个集合似乎看通用

Why is array calling Equals differently for struct[] and class[], even though both the collections seem to look generic?

该阵列的怪事是如此沮丧的是我想避免它完全...

The array weirdness is so frustrating that I'm thinking of avoiding it totally...

注意: 通用版等于被称为只有当结构的工具 IEquatable&LT; T&GT; 的如果类型不落实 IEquatable&LT; T&GT; 非泛型重载等于被称为不管它是结构

Note: The generic version of Equals is called only when the struct implements IEquatable<T>. If the type doesn't implement IEquatable<T>, non-generic overload of Equals is called irrespective of whether it is class or struct.

推荐答案

看来,它实际上不是Array.IndexOf(),它最终得到调用。纵观来源,我本来期望的Equals(对象)被调用在两种情况下,如果是这样的话。通过观察该点的堆栈跟踪,其中的Equals被调用,这使得它更清楚为什么你得到你所看到的(值类型得到的equals(动物)的行为,但引用类型得到的equals(对象)。

It appears that it's not actually Array.IndexOf() that ends up getting called. Looking at the source for that, I would have expected the Equals(object) to get called in both cases if that were the case. By looking at the stack trace at the point where the Equals gets called, it makes it more clear why you're getting the behavior you're seeing (value type gets Equals(Animal), but reference type gets Equals(object).

下面是值类型(结构动物)的堆栈跟踪

Here is the stack trace for the value type (struct Animal)

at Animal.Equals(Animal other)
at System.Collections.Generic.GenericEqualityComparer`1.IndexOf(T[] array, T value, Int32 startIndex, Int32 count)
at System.Array.IndexOf[T](T[] array, T value, Int32 startIndex, Int32 count)
at System.Array.IndexOf[T](T[] array, T value)
at System.SZArrayHelper.Contains[T](T value)
at System.Linq.Enumerable.Contains[TSource](IEnumerable`1 source, TSource value) 

下面是引用类型(对象动物)

Here is the stack trace for the reference type (object Animal)

at Animal.Equals(Object obj)
at System.Collections.Generic.ObjectEqualityComparer`1.IndexOf(T[] array, T value, Int32 startIndex, Int32 count)
at System.Array.IndexOf[T](T[] array, T value, Int32 startIndex, Int32 count)
at System.Array.IndexOf[T](T[] array, T value)
at System.SZArrayHelper.Contains[T](T value)
at System.Linq.Enumerable.Contains[TSource](IEnumerable`1 source, TSource value)

从这里就可以看出,它不是Array.IndexOf这是越来越称为 - 这是Array.IndexOf [T]。这种方法的最终使用平等comparers。在参照型的情况下,它使用ObjectEqualityComparer哪个呼叫的Equals(对象)。在值类型的情况下,它使用GenericEqualityComparer它调用的equals(动物),presumably避免昂贵的拳击。

From this you can see that it's not Array.IndexOf that's getting called - it's Array.IndexOf[T]. That method does end up using Equality comparers. In the case of the reference type, it uses ObjectEqualityComparer which call Equals(object). In the case of the value type, it uses GenericEqualityComparer which calls Equals(Animal), presumably to avoid an expensive boxing.

如果你看一下源$ C ​​$ c代表的IEnumerable在 http://www.dotnetframework.org
它有这个有趣的位上方:

If you look at the source code for IEnumerable at http://www.dotnetframework.org it has this interesting bit at the top:

// Note that T[] : IList<t>, and we want to ensure that if you use
// IList<yourvaluetype>, we ensure a YourValueType[] can be used
// without jitting.  Hence the TypeDependencyAttribute on SZArrayHelper.
// This is a special hack internally though - see VM\compile.cpp.
// The same attribute is on IList<t> and ICollection<t>.
[TypeDependencyAttribute("System.SZArrayHelper")]

我不熟悉TypeDependencyAttribute,但是从评论,我想知道是否有一些神奇的事情那是特殊的阵列。这也许可以解释的IndexOf [T]如何最终得到调用,而不是通过的IndexOf Array的IList.Contains。

I'm not familiar with TypeDependencyAttribute, but from the comment, I'm wondering if there is some magic going on that's special for Array. This may explain how IndexOf[T] ends up getting called instead of IndexOf via Array's IList.Contains.

这篇关于T []。包含结构和类不同的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆