![](/img/trans.png)
[英]Unreachable code when overriding Object.Equals and implementing IEquatable<>?
[英]What is the best way to test for object equality - without overriding Equals & GetHashCode, or implementing IEquatable<T>?
我想檢查兩個沒有公共屬性的對象之間的相等性。 但是,我不想重寫Equals和GetHashCode方法,或實現IEquatable。 例如,請考慮以下代碼:
class Program
{
static void Main(string[] args)
{
Guid id = Guid.NewGuid();
string personName = "MyName";
MyClass object1 = new MyClass(id, personName);
MyClass object2 = new MyClass(id, personName);
//This returns false, but I'd like it to return true:
Console.WriteLine(object1.Equals(object2));
//[edit]...by using, for example:
Console.WriteLine(ObjectsAreEqual(object1, object2));
}
}
class MyClass
{
private Guid _id;
private string _personName;
public MyClass(Guid id, string personName)
{
_id = id;
_personName = personName;
}
}
我知道標准方法是重寫Equals和GetHashCode,但由於各種原因,我不想更改類中的任何代碼。 此外,沒有公共財產,所以我無法比較這些。 有沒有其他方法來實現這個?
例如,通過反思? 或者可能通過將Objects序列化為JSON,並比較生成的字符串?
謝謝。
您可以創建一個使用反射的自定義IEqualityComparer<T>
實現:
var comparer = new MyClassEqualityComparer();
Console.WriteLine(comparer.Equals(object1, object2));
// ...
public class MyClassEqualityComparer : EqualityComparer<MyClass>
{
private static readonly string[] _names = { "_id", "_personName" };
private static readonly FieldInfo[] _infos =
typeof(MyClass).GetFields(BindingFlags.Instance | BindingFlags.NonPublic)
.Where(fi => _names.Contains(fi.Name))
.ToArray();
public override bool Equals(MyClass x, MyClass y)
{
return _infos.All(fi => object.Equals(fi.GetValue(x), fi.GetValue(y)));
}
public override int GetHashCode(MyClass obj)
{
unchecked
{
int hash = 31;
foreach (FieldInfo fi in _infos)
{
object val = fi.GetValue(obj);
hash = (hash * 17) + ((val == null) ? 0 : val.GetHashCode());
}
return hash;
}
}
}
如果不重寫它,則無法更改Equals
實例方法的結果。 因此,您需要使用IEqualityComparer<T>
,需要將其顯式傳遞給需要進行相等性檢查的代碼。 幸運的是,大多數內置集合都接受這樣的相等比較器作為其構造函數的參數。
如果您不想以任何方式更改原始類,則使用反射實現IEqualityComparer<T>
似乎是您唯一的選擇。
您可以使用GetField("_personName",BindingFlags.NonPublic)
獲取FieldInfo
,然后在其上調用GetValue
以獲取值。
void Main()
{
Guid id = Guid.NewGuid();
string personName = "MyName";
MyClass object1 = new MyClass(id, personName);
MyClass object2 = new MyClass(id, personName);
//This returns false, but I'd like it to return true:
Console.WriteLine(object1.Equals(object2));
//[edit]...by using, for example:
Console.WriteLine(MyClassEqualityComparer.Instance.Equals(object1, object2));
}
public class MyClass
{
private Guid _id;
private string _personName;
public MyClass(Guid id, string personName)
{
_id = id;
_personName = personName;
}
}
public class MyClassEqualityComparer:IEqualityComparer<MyClass>
{
private static FieldInfo personNameField=typeof(MyClass).GetField("_personName",BindingFlags.Instance|BindingFlags.NonPublic);
private static FieldInfo idField=typeof(MyClass).GetField("_id",BindingFlags.Instance|BindingFlags.NonPublic);
public bool Equals(MyClass o1,MyClass o2)
{
if(o1==o2)
return true;
if(o1==null||o2==null)
return false;
string name1=(string)personNameField.GetValue(o1);
string name2=(string)personNameField.GetValue(o2);
if(name1!=name2)
return false;
Guid id1=(Guid)idField.GetValue(o1);
Guid id2=(Guid)idField.GetValue(o2);
return id1==id2;
}
public int GetHashCode(MyClass o)
{
if(o==null)
return 0;
string name=(string)personNameField.GetValue(o);
Guid id=(Guid)idField.GetValue(o);
return name.GetHashCode()^id.GetHashCode();
}
private MyClassEqualityComparer()
{
}
public static readonly IEqualityComparer<MyClass> Instance=new MyClassEqualityComparer();
}
您可以向MyClass添加成員函數並檢查其中的私有字段:
class MyClass
{
private Guid _id;
private string _personName;
public MyClass(Guid id, string personName)
{
_id = id;
_personName = personName;
}
public bool IsEqual(MyClass otherInstance)
{
return (_id == otherInstance._id && _personName == otherInstance._personName);
}
}
或者,如果無法更改MyClass實現,則添加擴展方法,並使用反射進行比較,如CodeInChaos所述:
static class MyClassExtensions
{
public static bool IsEqual(this MyClass myInstance, MyClass otherInstance)
{
// Reflection goes here - read all private field from myInstance
// and otherInstance and compare them
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.