C# Net.Core Object.Equals() 即使两个对象相同也返回 false

C# Net.Core Object.Equals() returning false even if both objects are the same

我正在尝试 return 一个基于客户最喜欢的电影类型的推荐电影列表,而不包括那些已经是他最喜欢的电影。

所以,这是我的 Movie 对象

 public class Movie
{
    /// <summary>
    /// Movie's title
    /// </summary>
    public string Title { get; set; }
    
    /// <summary>
    /// Movie's gengres list
    /// </summary>
    public List<string> Genres { get; set; }

    private int HashCode 
    {
        get
        {
            return this.Title.GetHashCode();
        }
    }

    /// <summary>
    /// Public default constructor. Initializes an empty Movie object
    /// </summary>
    public Movie()
    {
        Genres = new List<string>();
    }

    /// <summary>
    /// Initializes a Movie object with a given title
    /// </summary>
    /// <param name="title">Movie title</param>
    public Movie(string title)
    {
        Title = title;
        Genres = new List<string>();
    }

    /// <summary>
    /// Override ToString function
    /// </summary>
    /// <returns>Movie's title</returns>
    public override string ToString()
    {
        return Title;
    }

    public override int GetHashCode()
    {
        return HashCode;
    }

    public override bool Equals(object obj)
    {
        if ((obj == null) || !this.GetType().Equals(obj.GetType()))
        {
            return false;
        }
        else
        {
            Movie movie = (Movie)obj;
            return (HashCode == movie.HashCode);
        }
    }
}

这是我的客户端对象

public class Client
{
    /// <summary>
    /// Client's First Name
    /// </summary>
    public string FirstName { get; set; }

    /// <summary>
    /// Client's Last Name
    /// </summary>
    public string LastName { get; set; }

    /// <summary>
    /// Client's full name
    /// </summary>
    public string FullName 
    {
        get
        {
            return $"{FirstName} {LastName}";
        }
    }

    /// <summary>
    /// Client's favorite movies
    /// </summary>
    public List<Movie> FavoriteMovies { get; set; }

    /// <summary>
    /// Public default constructor. Initializes an empty client
    /// </summary>
    public Client()
    {
        FavoriteMovies = new List<Movie>();
    }

    /// <summary>
    /// Initializes a client object with a given name
    /// </summary>
    /// <param name="firstName">Client's first name</param>
    /// <param name="lastName">Client's last name</param>
    public Client(string firstName, string lastName)
    {
        FirstName = firstName;
        FavoriteMovies = new List<Movie>();
    }

    /// <summary>
    /// Initializes a client object with given name and list of favorite movies
    /// </summary>
    /// <param name="firstName">Client's first name</param>
    /// <param name="lastName">Client's last name</param>
    /// <param name="favoriteMovies">Client's list of favorite movies</param>
    public Client(string firstName, string lastName, List<Movie> favoriteMovies)
    {
        FirstName = firstName;
        LastName = lastName;
        FavoriteMovies = favoriteMovies;
    }

    /// <summary>
    /// Override ToString function that will return Client's full name
    /// </summary>
    /// <returns>Client's full name</returns>
    public override string ToString()
    {
        return FullName;
    }

这是我的电影列表

        Movies = new List<Movie>();

        Movie movie1 = new Movie("Untitled Screenplay, adapted from the book, the Price of Fame, the biography of Dennis Price. Written by Eliane Parker and Gareth Owen.");
        movie1.Genres.Add("Action");
        Movies.Add(movie1);

        Movie movie2 = new Movie("Cannery Row");
        movie2.Genres.Add("Comedy");
        movie2.Genres.Add("Drama");
        movie2.Genres.Add("Romance");
        Movies.Add(movie2);

        Movie movie3 = new Movie("Body Melt");
        movie3.Genres.Add("Comedy");
        movie3.Genres.Add("Horror");
        movie3.Genres.Add("Sci-Fi");
        Movies.Add(movie3);

        Movie movie4 = new Movie("Ghost Lab");
        movie4.Genres.Add("Drama");
        movie4.Genres.Add("Horror");
        movie4.Genres.Add("Thriller");
        Movies.Add(movie4);

        Movie movie5 = new Movie("Biography: WWE Legends Biography: Booker T");
        movie5.Genres.Add("Action");
        Movies.Add(movie5);

        Movie movie6 = new Movie("Zombie Wars");
        movie6.Genres.Add("Action");
        Movies.Add(movie6);

        Movie movie7 = new Movie("Delitto in Formula Uno");
        movie7.Genres.Add("Comedy");
        movie7.Genres.Add("Crime");
        movie7.Genres.Add("Thriller");
        Movies.Add(movie7);

        Movie movie8 = new Movie("The Long and Winding Road");
        movie8.Genres.Add("Comedy");
        movie8.Genres.Add("Drama");
        Movies.Add(movie8);

我的客户会是这样的

        Client client2 = new Client("Belinda", "Reed");
        client2.FavoriteMovies.Add(movie2);
        client2.FavoriteMovies.Add(movie7);
        Clients.Add(client2);

这意味着 client2 最喜欢的电影名称是 Cannery Row(movie2)和 Formula Uno 中的 Delitto(movie7)。最喜欢的流派列表是

"Comedy"
"Drama"
"Romance"
"Crime"
"Thriller"

而 return 电影推荐的函数是

    public static List<Movie> MovieRecommendationsByClient(Client client, List<Movie> moviesCatalog)
    {
        var recommendations = moviesCatalog
            .Where(movie => client.FavoriteMovies
                                    .Any(cm => (!cm.Equals(movie)
                                        && cm.Genres.Intersect(movie.Genres).Any()))).ToList();


        return recommendations;
    }

理论上,基于客户最喜欢的电影类型列表而不包括他已经喜欢的类型的电影推荐应该是

"Body Melt"
"Ghost Lab"
"The Long and Winding Road"

但是断言失败了,因为 return 列表还包括 "Cannery Row""Delitto in Formula Uno"

我也这样试过,结果一样:

            var recommendations = from movie in moviesCatalog
                              from clientMovie in client.FavoriteMovies
                              where !clientMovie.Equals(movie) && movie.Genres.Intersect(clientMovie.Genres).Any()
                              group movie by movie into moviesGroup
                              select moviesGroup.Key;

我也试过比较 Movie Title 属性或 GetHashCode() 函数,但没有成功。

当我调试测试时,我可以看到 Equals(movie) return 是我期望的结果,所以我认为我在 LINQ 查询中做错了什么。

任何帮助将不胜感激

首先您可以排除客户列表中已有的电影,然后按流派组合进行过滤

有效:

   var recommendations = moviesCatalog.Except(client.FavoriteMovies)
            .Where(movie => client.FavoriteMovies
            .Any(cm => cm.Genres.Intersect(movie.Genres).Any())).ToList();