我正在尝试编写一种扩展方法,用于根据对象的字段比较对象。
我有这个:
public static class MyExtensions
{
public static bool FieldsEquals(this object o, object other)
{
if (ReferenceEquals(o, other))
return true;
if (o == null || other == null || o.GetType() != other.GetType())
return false;
foreach (var f in o.GetType().GetFields())
{
// is this a correct test ???
bool isEnumerable = f.FieldType != typeof(string) &&
typeof(IEnumerable).IsAssignableFrom(f.FieldType);
if (!isEnumerable)
{
if (!f.GetValue(o).Equals(f.GetValue(other)))
return false;
}
else
{
// convert both to IEnumerable and check if equal
}
}
return true;
}
}
我正在努力把这个领域当作一个收藏;我需要检测到这种情况,然后检查集合是否相同(元素数和f.GetValue(o)[i] == f.GetValue(other)[i]
相同。
有帮助吗?
答案 0 :(得分:2)
好吧,就像其他人已经提到的那样。边缘情况很多。
我建议对此类问题使用递归。
此方法还应该检查包含对象的数组或列表:
public static bool FieldsEquals(this object o1, object o2)
{
if (ReferenceEquals(o1, o2))
return true;
if (o1 == null || o2 == null || o1.GetType() != o2.GetType())
return false;
if (o1 is IEnumerable enumerable1 && o2 is IEnumerable enumerable2)
{
var enumerator1 = enumerable1.GetEnumerator();
var enumerator2 = enumerable2.GetEnumerator();
while(enumerator1.MoveNext())
{
if (!enumerator2.MoveNext())
{
return false;
}
if (!enumerator1.Current.FieldsEquals(enumerator2.Current))
{
return false;
}
}
}
else
{
foreach (var f in o1.GetType().GetFields())
{
var val1 = f.GetValue(o1);
var val2 = f.GetValue(o2);
if (val1 == null || val2 == null) continue;
if (val1 is IEnumerable e1 && val2 is IEnumerable e2)
{
if (!e1.FieldsEquals(e2))
{
return false;
}
}
else
{
if (!val1.Equals(val2))
{
return false;
}
}
}
}
return true;
}
答案 1 :(得分:1)
说实话,这里有很多问题。如果类型是基本类型(例如int)或结构(日期时间等)怎么办。如果可枚举字段包含的类不是基本类型怎么办?或属性是类?
有关深度平等的一些准则,请参见此问题:Compare the content of two objects for equality
所有这些,这就是我对您提到的代码的理解
public static bool FieldsEquals(this object o, object other)
{
if (ReferenceEquals(o, other)) return true;
if (o == null || other == null || o.GetType() != other.GetType()) return false;
foreach (var f in o.GetType().GetFields())
{
bool isEnumerable = f.GetValue(o).GetType().IsAssignableFrom(typeof(System.Collections.IEnumerable));// but is not a string
if (!isEnumerable)
{
if (!f.GetValue(o).Equals(f.GetValue(other))) return false;
}
else
{
var first = ((System.Collections.IEnumerable)f.GetValue(o)).Cast<object>().ToArray();
var second = ((System.Collections.IEnumerable)f.GetValue(other)).Cast<object>().ToArray();
if (first.Length != second.Length)
return false;
for (int i = 0; i < first.Length; i++)
{
if (first[i] != second[i]) //assumes they are basic types, which implement equality checking. If they are classes, you may need to recursively call this method
return false;
}
}
}
return true;
}