HashSet.IntersectWIth使用自定义的IEqualityComparer在Mono中产生错误的结果
本文关键字:结果 错误 Mono IEqualityComparer IntersectWIth 自定义 HashSet | 更新日期: 2023-09-27 18:11:52
我遇到的问题是,某段代码在。net 4.0中按预期运行,但在Mono 2.6(在Unity3D中)中没有。请看:
void Test()
{
Func<string, MemberInfo> get = name => typeof(HSTest).GetField(name, BindingFlags.Public | BindingFlags.Instance);
var m1 = new TestMember { MemberInfo = get("x") };
var m2 = new TestMember { MemberInfo = get("y") };
var m3 = new TestMember { MemberInfo = get("x") };
var m4 = new TestMember { MemberInfo = get("x") };
var m5 = new TestMember { MemberInfo = get("a") };
var m6 = new TestMember { MemberInfo = get("b") };
var l1 = new List<TestMember> { m1, m2, m3 };
var l2 = new List<TestMember> { m4, m5, m6 };
var ll = new List<List<TestMember>> { l1, l2 };
var comparer = new TestMemberComparer();
var res = IntersectAll(ll, comparer);
res.Foreach(Debug.Log); // In .NET this prints "x" in Mono it doesn't print anything
}
// Credits to Jon Skeet
public static List<T> IntersectAll<T>(List<List<T>> lists, IEqualityComparer<T> comparer)
{
HashSet<T> hashSet = null;
foreach (var list in lists)
{
if (hashSet == null)
{
hashSet = new HashSet<T>(list, comparer);
}
else
{
hashSet.IntersectWith(list);
}
}
return hashSet == null ? new List<T>() : hashSet.ToList();
}
}
public class TestMember
{
public MemberInfo MemberInfo { get; set; }
}
public class TestMemberComparer : IEqualityComparer<TestMember>
{
public bool Equals(TestMember x, TestMember y)
{
return x.MemberInfo.Equals(y.MemberInfo);
}
public int GetHashCode(TestMember obj)
{
return obj.MemberInfo.GetHashCode();
}
}
public class HSTest
{
public int x;
public int y;
public int z;
public int a;
public int b;
public int c;
}
在。net中,我得到'x'作为交集的结果,在Mono中,我没有得到任何回报。
任何想法?
编辑:使用名称而不是实际的MemberInfo对象也没有帮助
public class TestMemberComparer : IEqualityComparer<TestMember>
{
public bool Equals(TestMember x, TestMember y)
{
return x.MemberInfo.Name.Equals(y.MemberInfo.Name);
}
public int GetHashCode(TestMember obj)
{
return obj.MemberInfo.Name.GetHashCode();
}
}
我还应该提到,使用不同的方式相交不会引起任何问题(无论是在GetHashCode
和Equals
中使用MemberInfo
和MemberInfo.Name
时):
var res = ll.Aggregate((p, n) => p.Intersect(n, comparer).ToList());
编辑:下面是比较器
内的一些日志的测试 void Test()
{
// ... define everything like in previous code
var comparer = new TestMemberComparer();
var hs = new HashSet<TestMember>(l1, comparer);
hs.IntersectWith(l2);
hs.ToList().Foreach(Debug.Log);
}
public class TestMemberComparer : IEqualityComparer<TestMember>
{
public bool Equals(TestMember left, TestMember right)
{
bool result = left.MemberInfo.Name.Equals(right.MemberInfo.Name);
Debug.Log("Comparing `" + left.MemberInfo.Name + "` with `" + right.MemberInfo.Name + "` Result: " + result);
return result;
}
public int GetHashCode(TestMember obj)
{
int hc = obj.MemberInfo.Name.GetHashCode();
Debug.Log("Hash code: " + hc);
return hc;
}
}
执行时得到的结果是:
Hash code: 120
Hash code: 120
Hash code: 121
Comparing `x` with `x` Result: True
Hash code: 120
Hash code: 120
Hash code: 120
Comparing `x` with `x` Result: True
Hash code: 121
Comparing `y` with `y` Result: True
Hash code: 97
Hash code: 97
Hash code: 98
Hash code: 98
我怀疑这只是MemberInfo.Equals
不像你期望的那样工作的问题。这很容易测试:
var m1 = get("x");
var m2 = get("x");
Console.WriteLine(m1.Equals(m2));
如果输出False,那就是问题了,你应该添加你自己的缓存