请参阅以下代码:
public virtual bool Equals(T other)
{
if (other == null)
return false;
Type t = GetType();
Type otherType = other.GetType();
if (t != otherType)
return false;
FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
foreach (FieldInfo field in fields)
{
object value1 = field.GetValue(other);
object value2 = field.GetValue(this);
if (value1 == null)
{
if (value2 != null)
return false;
}
else if (!value1.Equals(value2))
return false;
}
return true;
}
假设value1和value2是字符串数组。即使数组具有相同的内容,上面的代码也会返回false。如果它们包含相同的内容,我如何确保返回true?
我看过这里:How to compare arrays in C#?并尝试了这个:
bool isEqual = Enumerable.SequenceEqual(value1, value2);
编译器错误是:无法从使用中推断出SequenceEqual。
答案 0 :(得分:1)
部分问题是field.GetValue(other)
会返回object
。您可能会发现使用递归反射来比较无类型对象会让您感到沮丧。
为了完成这项工作,您必须确定该字段是否为集合,如果是,则比较集合的内容。那么如果其中一个集合包含集合呢?这是可行的,但它很头疼。
无论您正在尝试比较这个对象,如果您为要比较的类型实施IEquatable<T>
或定义IEqualityComparer<T>
,情况就会简单得多。然后,您的Equals
方法会明确检查各个成员的相等性。如果这些成员是引用类型,那么您也可以为这些成员定义相等性。然后,如果这些类型具有更多嵌套属性,则不必深入查看所有嵌套属性并比较它们的属性。
这最终需要的是你的方法&#34;知道&#34;它的类型是什么类型,以便它确切地知道如何比较它们。如果您使用反射来确定属性是什么,然后尝试检查它们是否相等,那么它是可能的,但它很难并且可能会被未来的更改所打破。
这是一个使用嵌套属性的几个类的例子。
public class Foo : IEquatable<Foo>
{
public int FooValue { get; set; }
public List<Bar> Bars { get; set; }
public bool Equals(Foo other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
if (FooValue != other.FooValue) return false;
if (Bars == null ^ other.Bars == null) return false;
return Bars == null || Bars.SequenceEqual(other.Bars);
}
}
public class Bar : IEquatable<Bar>
{
public int BarValue { get; set; }
public List<FooBar> FooBars { get; set; }
public bool Equals(Bar other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
if( BarValue != other.BarValue) return false;
if (FooBars == null ^ other.FooBars == null) return false;
return FooBars==null || FooBars.SequenceEqual(other.FooBars);
}
}
public class FooBar : IEquatable<FooBar>
{
public int FooBarValue { get; set; }
public bool Equals(FooBar other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return FooBarValue == other.FooBarValue;
}
}
每个具有嵌套集合属性的类都使用SequenceEqual
来确定集合是否匹配。但是,它如何判断这些集合中的个别项目是否相等?它没有。它假定这些类型将能够确定相等。
现在,如果使类的两个实例相等的条件发生变化,则可以将详细信息隔离到该类。
假设我无法修改其中一个类以支持IEquatable<T>
,或者由于某种原因它没有意义。也许平等在不同的背景下有不同的决定。也许一个类有ID
属性,在某些情况下我所关心的是,如果两个对象具有相同的ID
,它们就相等。
在这种情况下,我可以将相等比较移动到它自己的类中,并且只在我想要的时候使用它。它不再是&#34;内置&#34;上课。
public class FooBar
{
public int FooBarValue { get; set; }
}
public class FooBarComparer : IEqualityComparer<FooBar>
{
public bool Equals(FooBar x, FooBar y)
{
if (ReferenceEquals(x, y)) return true;
if (x == null || y == null) return false;
return x.FooBarValue == y.FooBarValue;
}
public int GetHashCode(FooBar obj)
{
return obj.GetHashCode();
}
}
现在当我在SequenceEqual
的两个集合上使用FooBar
时,我会这样做:
FooBars.SequenceEqual(other.FooBars, new FooBarComparer())
这样做的另一个好处是可以重复使用相等比较。假设您有两个不同的类,其列表为Bar
。现在,这两个类都不必检查Bar
及其嵌套属性以确定相等性,这将重复代码。该等级检查位于其他地方,并且可以在两者共享时进行共享。
答案 1 :(得分:0)
这个问题很可能与参考等于与价值平等有关。如果比较2个不重写等于的对象,则表示它们是相同的项目,而不是相同的值。
您看到的SequenceEqual错误与编译器无法确定您用于比较的类型有关。
https://msdn.microsoft.com/en-us/library/bb348567(v=vs.110).aspx
您可以指定要用于检查相等性的类型
public List<MyUser> getList(String stringJson){
List<MyUser> myUser = null;
Gson gson = new Gson();
Type type = new TypeToken<List<MyUser>>() {}.getType();
myUser = gson.fromJson(stringJson, type);
return myUser;
}