C# HashSet.IntersectWIth使用自定义IEqualityComparer会在Mono中产生错误的结果

C# HashSet.IntersectWIth使用自定义IEqualityComparer会在Mono中产生错误的结果,c#,mono,intersection,hashset,iequalitycomparer,C#,Mono,Intersection,Hashset,Iequalitycomparer,我遇到了一个问题,某段代码在.NET4.0中按预期运行,但在Mono2.6(Unity3D)中却没有。请看一看: void Test() { Func<string, MemberInfo> get = name => typeof(HSTest).GetField(name, BindingFlags.Public | BindingFlags.Instance); var m1 = new TestMember { Membe

我遇到了一个问题,某段代码在.NET4.0中按预期运行,但在Mono2.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;
}
编辑:这是一个在比较器中有一些日志的测试

    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;
    }
}

我怀疑这只是
MemberInfo.Equals
没有按您的预期工作的问题。这很容易测试:

var m1 = get("x");
var m2 = get("x");
Console.WriteLine(m1.Equals(m2));

如果打印错误,那么这就是问题所在,您应该添加自己的缓存。

谢谢您的回复。你是对的,它打印出来是假的。但是有两件事:1-它在.NET中工作得很好,但在Mono中却不行,为什么?2-我写了
m1.MemberInfo.Equals(m2.MemberInfo)
而不是
m1.Equals(m2.MemberInfo)
并打印为true!-我猜
m1.Equals
正在解析为
对象。Equals
在这种情况下?我还尝试使用
MemberInfo.Name
而不是
IEqualityComparer
Equals
GetHashCode
中的
MemberInfo
。交集中仍然没有任何内容。@vexe:我怀疑.NET每次都使用缓存返回对同一MemberInfo对象的引用。给定我的代码,
m1.MemberInfo
不应该编译。(我没有使用您的`TestMember类。)是的,但是
MemberInfo.Name
呢?我在
Equals
GetHashCode
中使用了它,但仍然是一样的。。。不应该是同一个名字吗?@vexe:是的,应该可以。请给出一个简短但完整的示例,说明该方法不起作用。
    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
var m1 = get("x");
var m2 = get("x");
Console.WriteLine(m1.Equals(m2));