RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 841939
Accepted
Алексей Федотов
Алексей Федотов
Asked:2020-06-14 17:33:28 +0000 UTC2020-06-14 17:33:28 +0000 UTC 2020-06-14 17:33:28 +0000 UTC

如果 Equals() 在 Object 中,为什么要实现 IEquatable<T>?

  • 772

处理泛型主题(根据 Shield 4.0),有必要编写一个泛型方法,如果数组包含某个值,该方法将返回布尔值 true。本书继续解释说,由于 T 是泛型类型,为了比较泛型类型的对象,这些对象的类必须实现带有 T 或 IEquatable 参数的 IEquatable 接口。还写到在这些接口中定义了一个比较 Equals() 的方法。这立即导致几个问题:

首先,为什么我们需要实现任何接口来比较泛型类型对象?Equals() 方法是指 Object => 中定义的方法,存在于每个对象中。我意识到为了在这个例子中比较对象,你需要实现上面描述的接口,但我不明白为什么要这样做。

其次,根据 Shield,正如我上面写的,为了比较泛型方法中的对象,建议使用参数 T 或 IEqutable 来实现 Equtable。一个是参数化的,另一个不是。问题是在哪种情况下应该使用哪一个?

此外,在他的书中,Shield 演示了一个检查值是否在数组中的方法示例。这是方法:

 public static bool IsIn<T>(T what, T[] obs) where T : IEquatable<T>
    {
        foreach(T v in obs)
        {
            if (v.Equals(what))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }

这里还有两个问题。

首先,让我先说这种方法行不通。工作室产生编译错误“并非所有方法分支都返回值”。我重新检查了几次编写的代码,但错误仍然存​​在。如何解决?

其次,我不确定我是否正确理解该方法的签名意味着只有实现 IEquatable 接口的那些类型的对象才能传递给该方法?换句话说,如果我想将一些学生的数组传递给该方法并在其中找到 Vasya Pupkin,那么我的学生类应该是这样的?

class Student<T> : IEquatable<T>
{
    public string Name;
    public string Surname;

    public bool Equals(T other)
    {
        //some code for compare
        return false;
    }
}

请按顺序回答所有问题。谢谢

c#
  • 3 3 个回答
  • 10 Views

3 个回答

  • Voted
  1. Best Answer
    Pavel Mayorov
    2020-06-14T19:39:10Z2020-06-14T19:39:10Z

    该接口IEquatable<>旨在避免在比较时对值类型进行不必要的打包。

    只要每个人都对对象感到满意并且只使用它们,该方法object.Equals(object)就没有特别的缺点(过度类型转换并不是特别可怕的缺点)。但是当泛型类型出现在语言中时,事情变得更糟了。

    尝试object.Equals(object other)在值类型上调用方法会导致:

    1. 空参数(this)被装箱并分配在堆上,
    2. 第一个参数(其他)在堆上打包并分配,
    3. 两个参数都被解包并比较,
    4. 参数的打包副本被遗忘(下次打包将再次发生)。

    一般来说,泛型类型的发明正是为了避免不必要的结构装箱,所以仅仅为了比较而需要装箱是一场灾难。事实上,System.Collections.Generics.Dictionary<,>由于不断包装,泛型集合的性能甚至可能比旧变体更差System.Collections.Hashtable。

    因此,发明了一个新接口,允许您比较两个值而无需类型转换(因此,无需打包)。


    现在谈谈你的方法。首先,书中的建议并不完全正确:标准库对这些方法有不同的约定。如果前者不可用IEquatable<>,您可以使用EqualityComparer<>内部使用IEquatable<>旧方法或旧方法的类,而不需要实现。object.Equals此外,最好有机会将任何实现传递给该方法IEqualityComparer<>(例如,比较字符串而不考虑大小写)。

    这样会更正确:

    public static bool IsIn<T>(T what, T[] obs, IEqualityComparer<T> comparer = null)
    {
        if (comparer == null) comparer = EqualityComparer<T>.Default;
    
        foreach(T v in obs)
        {
            if (comparer.Equals(what, v))
            {
                return true;
            }
        }
    
        return false;
    }
    

    (嗯,我已经写过这里方法中的第二个错误:两个分支都在条件运算符中执行 // 数组搜索不起作用)

    使用这种方法的实现,它可以像简单的类一样使用(这些类的对象通过引用简单地比较):

    class Student
    {
        public string Name;
        public string Surname;
    }
    

    以及更高级的:

    sealed class Student : IEquatable<Student>
    {
        public readonly string Name;
        public readonly string Surname;
    
        public Student(string name, string surname)
        {
            Name = name;
            Surname = surname;
        }
    
        public override bool Equals(object other) => Equals(other as Student);
        public bool Equals(Student other) 
        {
            if (this == other) return true;
            if (other == null) return false;
            if (Name != other.Name) return false;
            if (Surname!= other.Surname) return false;
            return true;
        }
        public override int GetHashCode()
        {
            unchecked 
            {
                // https://stackoverflow.com/a/263416/4340086
                int hash = 2166136261;
                hash = (16777619 * hash) ^ (Name?.GetHashCode() ?? 0);
                hash = (16777619 * hash) ^ (Surname?.GetHashCode() ?? 0);
                return hash;
            }
        }
    }
    
    • 13
  2. Zergatul
    2020-06-14T18:09:40Z2020-06-14T18:09:40Z

    Equals(object obj)最开始出现在 .NET 中,然后还没有泛型。在 .NET 2.0 中引入泛型之前,Equals(object obj)大多数情况下的方法覆盖看起来像这样:

    public bool override Equals(object obj)
    {
        if (obj == null)
            return false;
        if (obj is MyClass)
        {
            MyClass other = (MyClass)obj;
            // сравниваем this и other
        }
        return false;
    }
    

    事实证明,在大多数情况下,不同类型的对象不可能相等。为了让生活更轻松,我们提出了一个界面IEquatable<T>,您可以在其中立即比较 2 个对象,而无需检查它们的类型(这也需要一些时间)。

    以一种好的方式,现在您应该IEquatable<T>为所有可以比较的类实现。同时,您不应该忘记重新定义旧Equals版本,以实现兼容性。例如,您可以这样做:

    public bool override Equals(object obj)
    {
        return Equals(obj as MyClass);
    }
    
    public bool Equals(MyClass other)
    {
        if (other== null)
            return false;
        // сравниваем объекты
    }
    
    • 9
  3. mazzy
    2020-06-14T17:53:34Z2020-06-14T17:53:34Z

    关于“不是所有的方法分支都返回值”:如果obs为空,那么里面的代码foreach永远不会被执行,因此方法不会满足任何return语句。因此错误。

    据我了解,方法代码应该是这样的:

    public static bool IsIn<T>(T what, T[] obs) where T : IEquatable<T>
    {
        foreach(T v in obs)
        {
            if (v.Equals(what))
            {
                return true;
            }
        }
        return false;
    }
    

    是的,此方法的签名意味着只有实现 IEquatable 接口的类型的对象才能传递给此方法。

    • 4

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    是否可以在 C++ 中继承类 <---> 结构?

    • 2 个回答
  • Marko Smith

    这种神经网络架构适合文本分类吗?

    • 1 个回答
  • Marko Smith

    为什么分配的工作方式不同?

    • 3 个回答
  • Marko Smith

    控制台中的光标坐标

    • 1 个回答
  • Marko Smith

    如何在 C++ 中删除类的实例?

    • 4 个回答
  • Marko Smith

    点是否属于线段的问题

    • 2 个回答
  • Marko Smith

    json结构错误

    • 1 个回答
  • Marko Smith

    ServiceWorker 中的“获取”事件

    • 1 个回答
  • Marko Smith

    c ++控制台应用程序exe文件[重复]

    • 1 个回答
  • Marko Smith

    按多列从sql表中选择

    • 1 个回答
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Suvitruf - Andrei Apanasik 什么是空? 2020-08-21 01:48:09 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5