如果我有一个像这样的对象:
public class Person
{
public int id {get;set;}
public string name {get;set;}
}
我想要这个行为:
Person a = new Person();
Person b = new Person();
a == b;
并且a == b返回true,我是否必须覆盖Object.Equals()方法?还是有其他方法可以不覆盖Equals方法吗?
修改
我想比较数据,因为我想知道我调用的外部方法是否返回新对象或具有与新对象不同的数据的对象
答案 0 :(得分:17)
有几种方法可以做到这一点。默认情况下Equals()
和==
检查引用相等性,意思是:
Person a = new Person();
Person b = a:
a.Equals(b); //true
a == b; //true
因此,不会将对象与值相等进行比较,这意味着:
Person a = new Person { id = 1, name = "person1" };
Person b = new Person { id = 1, name = "person1" };
a.Equals(b); //false
a == b; //false
要比较对象的值,您可以覆盖Equals()
和GetHashcode()
方法,如下所示:
public override bool Equals(System.Object obj)
{
if (obj == null)
return false;
Person p = obj as Person;
if ((System.Object)p == null)
return false;
return (id == p.id) && (name == p.name);
}
public bool Equals(Person p)
{
if ((object)p == null)
return false;
return (id == p.id) && (name == p.name);
}
public override int GetHashCode()
{
return id.GetHashCode() ^ name.GetHashCode();
}
现在,您将在比较时看到其他结果:
Person a = new Person { id = 1, name = "person1" };
Person b = new Person { id = 1, name = "person1" };
Person c = a;
a == b; //false
a == c; //true
a.Equals(b); //true
a.Equals(c); //true
==
运算符未被覆盖,因此仍然会进行引用比较。这可以通过重载它以及!=
运算符来解决:
public static bool operator ==(Person a, Person b)
{
if (System.Object.ReferenceEquals(a, b))
return true;
if ((object)a == null || (object)b == null)
return false;
return a.id == b.id && a.name == b.name;
}
public static bool operator !=(Person a, Person b)
{
return !(a == b);
}
现在运行检查结果如下:
Person a = new Person { id = 1, name = "person1" };
Person b = new Person { id = 1, name = "person1" };
Person c = a;
a == b; //true
a == c; //true
a.Equals(b); //true
a.Equals(c); //true
更多阅读:
答案 1 :(得分:2)
这一切都取决于您要比较的内容,默认情况下Equals
将按参考进行比较
a == b
您的示例中的始终为false
。但是,如果你做了类似
Person a = new Person();
Person b = a;
然后a == b
将为true
,因为a
和b
都使用相同的引用。
我是否必须覆盖Object.Equals()方法?
但是,推荐的方法是覆盖Equals和GetHashCode(为了论证),这不是唯一的方法。例如,您可以覆盖==
运算符并在那里进行比较。但是,单独沿着那条路走下去是有局限的。
大多数比较检查(如果不是全部)将在内部使用Equals
,这就是为什么它是首选方法。请参阅Guidelines for Implementing Equals and the Equality Operator (==)。
答案 2 :(得分:2)
您想要重载==
运算符。因此,您还应首先覆盖Equals
。如果您覆盖Equals
,则应始终覆盖GetHashCode
。如果您重载==
运算符,则还必须重载!=
运算符:
public class Person
{
public int id {get;set;}
public string name {get;set;}
public override bool Equals(object obj)
{
Person p2 = obj as Person;
if (object.ReferenceEquals(null, p2)) return false;
return id == p2.id;
}
public static bool operator ==(Person p1, Person p2)
{
if (object.ReferenceEquals(null, p1))
return object.ReferenceEquals(null, p2);
else if (object.ReferenceEquals(null, p2))
return false;
return p1.Equals(p2);
}
public static bool operator !=(Person p1, Person p2)
{
if (object.ReferenceEquals(null, p1))
return !object.ReferenceEquals(null, p2);
else if (object.ReferenceEquals(null, p2))
return true;
return !p1.Equals(p2);
}
public override int GetHashCode()
{
return id ;
}
}
现在比较值(id
)而不仅仅是引用:
Person p1 = new Person { id = 1, name = "Jeff" };
Person p2 = new Person { id = 2, name = "Tim" };
bool equalPersons = p1 == p2; // false
Person p3 = new Person { id = 1, name = "Jeff 2.0" }; // same id -> equal
equalPersons = p1 == p3; // true
MSDN: Guidelines for Implementing Equals and the Equality Operator (==)
答案 3 :(得分:0)
object.Equals(object2);
在你的情况下:
a.Equals(b);
答案 4 :(得分:0)
假设测试是Class
Test a = new Test() { Num = 1, Str = "Hi" };
Test b = new Test() { Num = 1, Str = "Hi" };
bool areEqual = System.Object.ReferenceEquals(a, b);
答案 5 :(得分:0)
是。您想要与Person的对象进行比较,您需要从Object类重写equals和hashcode方法,因为默认情况下,引用check(==)是通过equals方法完成的。
假设两个具有相同名称和id的人只能被视为相等,则在equals和hashcode方法中使用这两个属性。
使用Java IDE提供的生成equals和hashcode更容易。你可以尝试下面的代码。
public class Person {
private int id;
private String name;
// id getters and setters
// name getters and setters
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
答案 6 :(得分:0)
在C#9.0及更高版本中,有一个名为record
的新类型,其相等性基于值。因此,您可以将其定义为:
public record Person
{
public string LastName { get; }
public string FirstName { get; }
public Person(string first, string last) => (FirstName, LastName) = (first, last);
}
然后您就可以使用
var bill1 = new Person("Bill", "Wagner");
var bill2 = new Person("Bill", "Wagner");
Console.WriteLine(bill1 == bill2); // true
参考: https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9#record-types
答案 7 :(得分:0)
如果你愿意,你可以写一个这样的扩展方法(创建一个这样的新类):
public static class Extensions
{
public static bool IsEqual<T>(this T objA, T objB)
{
foreach (var item in objA.GetType().GetProperties())
{
if (item.GetValue(objA).ToString() != item.GetValue(objB).ToString())
return false;
}
return true;
}
}
}
然后你可以使用这种扩展方法:
Person a = new Person { id = 1, name = "person1" };
Person b = new Person { id = 1, name = "person1" };
....
if ( a.IsEqual<Person>(b)) // this returns true ;)
{
do something ...
}
else
{
do something else ...
}
....
享受吧。