为什么我在执行交集时得不到结果?

Why am I not getting results when performing an intersection?

用户class:

public class User  
{
    public int ID { get; set; }
    public string Email { get; set; }
}

代码:

        var usersL = new List<User>()
                        {
                            new User{ID = 1,Email = "abc@foo.com"},
                            new User{ID = 2,Email = "def@foo.com"}
                        };

        var usersR = new List<User>()
                        {
                            new User{ID = 1,Email = "abc@foo.com"},
                            new User{ID = 2,Email = "def@foo.com"}
                        };

        var both = (from l in usersL select l)
            .Intersect(from users in usersR select users);

        foreach (var r in both)
            Console.WriteLine(r.Email);

其中 returns 0 个结果。

我知道我可以通过使用 join 来完成类似的事情,但我想使用 Intersect,因为 A) 这最终会在某些数据库代码上起作用,我们想使用这个函数(太长了,无法解释为什么)和 B) 我只是很好奇为什么 Intersect 在这里不起作用。

        var both = from l in usersL
                   join r in usersR on l.ID equals r.ID
                   select l;

.Net 提供预定义类型的比较逻辑。在您的连接查询的情况下,您正在连接(比较)两个 Int 类型的 ID(预定义类型)

var both = from l in usersL
           join r in usersR on l.ID equals r.ID
           select l;

在交叉查询的情况下,您正在尝试比较用户类型的两个用户定义的自定义对象。因此,您需要提供自己的自定义比较实现逻辑。

2 种方法 来解决这个...

选项 1: 实施 IEqualityComparer

public class User
{
    public int ID { get; set; }
    public string Email { get; set; }
}

public class MyEqualityComparer : IEqualityComparer<User>
{
    public bool Equals(User x, User y)
    {
        if (object.ReferenceEquals(x, y))
            return true;
        if (x == null || y == null)
            return false;
        return x.ID.Equals(y.ID) &&
               x.Email.Equals(y.Email);
    }

    public int GetHashCode(User u)
    {
        return new { u.ID, u.Email }.GetHashCode();
    }
}

class Program
{
    static void Main(string[] args)
    {

        var usersL = new List<User>()
                    {
                        new User{ID = 1,Email = "abc@foo.com"},
                        new User{ID = 2,Email = "def@foo.com"}
                    };

        var usersR = new List<User>()
                    {
                        new User{ID = 1,Email = "abc@foo.com"},
                        new User{ID = 2,Email = "def@foo.com"}
                    };

        var both =  (from l in usersL select l)
          .Intersect(from users in usersR select users, new MyEqualityComparer());

        foreach (var r in both)
            Console.WriteLine(r.Email);
    }
}

选项 2覆盖自定义对象本身的 Equals 和 GetHashcode 方法

public class User 
{
    public int ID { get; set; }
    public string Email { get; set; }

    public override bool Equals(Object obj)
    {
        // Check for null values and compare run-time types.
        if (obj == null || GetType() != obj.GetType())
            return false;

        User x = (User)obj;
        return (ID == x.ID) && (Email == x.Email);
    }

    public override int GetHashCode()
    {
        return new { ID, Email }.GetHashCode();
    }
}

class Program
{
    static void Main(string[] args)
    {

        var usersL = new List<User>()
            {
                new User{ID = 1,Email = "abc@foo.com"},
                new User{ID = 2,Email = "def@foo.com"}
            };

        var usersR = new List<User>()
            {
                new User{ID = 1,Email = "abc@foo.com"},
                new User{ID = 2,Email = "def@foo.com"}
            };

        var both = (from l in usersL select l)
          .Intersect(from users in usersR select users);

        foreach (var r in both)
            Console.WriteLine(r.Email);
    }
}

希望这对您有所帮助。

这是对@sundeep 的回应,他说 "Now regards to your 2nd question... "(我希望你能 link 发表评论)——我只是创建一个新答案,因为我不想毁了我原来问题的背景

用户 class 实施 IEqualityComparer

public class User : IEqualityComparer<User>
{
    public int ID { get; set; }
    public string Email { get; set; }

    public bool Equals(User x, User y)
    {
        if (object.ReferenceEquals(x, y))
            return true;
        if (x == null || y == null)
            return false;
        return x.ID.Equals(y.ID) &&
               x.Email.Equals(y.Email);
    }

    public int GetHashCode(User obj)
    {
        return new { obj.ID, obj.Email }.GetHashCode();
    }
}

交叉点returns没有行:

        var usersL = new List<User>()
                        {
                            new User{ID = 1,Email = "abc@foo.com"},
                            new User{ID = 2,Email = "def@foo.com"}
                        };

        var usersR = new List<User>()
                        {
                            new User{ID = 1,Email = "abc@foo.com"},
                            new User{ID = 2,Email = "def@foo.com"}
                        };

        var both = (from l in usersL select l)
            .Intersect(from users in usersR select users);

        foreach (var r in both)
            Console.WriteLine(r.Email);