这是我自己的问题的解决方案。我不得不承认,从一开始我就不清楚我想要完成什么,这在最初的帖子的编辑中很明显。第一个代码示例是对其他人在此站点上发布的类似问题的回答。它本质上是非常通用的,但是您可以清楚地看到此人试图提倡通过返回相同的对象类型来链接方法。在观看了 Zoran Horvat 的名为“让你的 C# 代码更加面向对象”的教程之后,我想完成类似的事情。本教程可在 Pluralsight 上找到。他的例子是在第 4 章和第 5 章中使用接口和扩展方法。这个解决方案的想法有些相似,但我希望将这个功能包含在单个类中。
我认为整个混淆与该方法需要返回的对象类型有关,以便提供链接功能。让我们看一些简单的字符串示例
someString.ToUpper.ToLower.Trim
我们首先想到的是字符串从一个方法传递到另一个方法,并且在每一步都被该方法修改。因此,我们在处理集合时会遇到类似的情况。
movies.GetByYear(1999).GetByGroup(1).GetByGenre("Action")
在这种情况下,我们从一些通过这个方法链传递的 List 开始。我们也很可能认为这条链中的所有方法都在同一个 List 上运行。毕竟,上一个示例中的字符串属性在所有方法之间共享,即使它正在被修改。这不是这一系列电影实际发生的情况。每种方法都适用于具有不同大小的集合。看起来 GetByYear() 和 GetByGroup() 是处理相同电影列表的方法,它们实际上是具有完全不同列表的独立库对象。
我要感谢 Sokohavi,他对返回 Library 对象发表了评论。他还建议将库对象设为 IEnumerable。不幸的是,如果您认为该方法应该返回 IEnumerable,那么您就走错了路。从技术上讲,Library 是一个 List,但保存 Movie 对象的列表设置为私有,对其他对象不可见。因此没有什么可以迭代的。库对象只有几个方法,如果您选择其中一个,您将无法访问同一类中的其他方法。因此方法必须返回Library 对象才能访问同一类中的所有方法,并且存储Movie 对象的列表必须是IEnumerable。这种方法有一个缺点。您不能在库构造函数中将数据加载到此列表中。相反,数据作为 Parameter 传递。现在,您拥有具有不同电影列表的对象,并且它们之间的通信方式是通过它们的构造函数。
下面我们有 Repository 类,它通过其构造函数将单个项目加载到列表中。库类定义的方法将提供对传递给它的列表的过滤。您还可以创建另一个抽象层来使用该功能。
public class Movie
{
public string Title { get; set; }
public int Year { get; set; }
public int GroupId { get; set; }
public string Genre { get; set; }
}
public class Repository
{
private List<Movie> localDb;
public Repository()
{
localDb = new List<Movie>();
}
public IEnumerable<Movie> GetAllMovies()
{
localDb = new List<Movie>();
var movie1 = new Movie() { Title = "Movie1", Year = 2000, GroupId = 1, Genre = "Action" };
var movie2 = new Movie() { Title = "Movie2", Year = 1999, GroupId = 1, Genre = "Drama" };
var movie3 = new Movie() { Title = "Movie3", Year = 2000, GroupId = 1, Genre = "Comedy" };
var movie4 = new Movie() { Title = "Movie4", Year = 2000, GroupId = 2, Genre = "Action" };
var movie5 = new Movie() { Title = "Movie5", Year = 1999, GroupId = 2, Genre = "Drama" };
var movie6 = new Movie() { Title = "Movie6", Year = 1999, GroupId = 2, Genre = "Drama" };
var movie7 = new Movie() { Title = "Movie7", Year = 1999, GroupId = 2, Genre = "Horror" };
localDb.Add(movie1);
localDb.Add(movie2);
localDb.Add(movie3);
localDb.Add(movie4);
localDb.Add(movie5);
localDb.Add(movie6);
localDb.Add(movie7);
return localDb;
}
}
public class Library
{
private IEnumerable<Movie> MoviesLibrary;
public Library(IEnumerable<Movie> movies)
{
this.MoviesLibrary = movies.ToList();
}
public Library GetByYear(int year)
{
return new Library(this.MoviesLibrary.Where(movie => movie.Year == year));
}
public Library GetById(int id)
{
return new Library(this.MoviesLibrary.Where(movie => movie.GroupId == id));
}
public IEnumerable<Movie> GetByGenre(string genre)
{
return this.MoviesLibrary.Where(movie => movie.Genre == genre);
}
public void Display()
{
foreach (var movie in this.MoviesLibrary)
{
Console.WriteLine("Title: {0} , Year {1}, Group: {2}, Genre: {3}", movie.Title,movie.Year,movie.GroupId, movie.Genre);
}
}
}
如何使用这些类:
var repository = new Repository();
var listOfMovies = repository.GetAllMovies();
var movies = new Library(listOfMovies);
var selectedMovies1 = movies.GetByYear(2000).GetById(1).GetByGenre("Action");
var selectedMovies2 = movies.GetByYear(2000).GetById(2);
foreach (var movie in selectedMovies1)
{
Console.WriteLine("Selected 1 - Title: {0} , Year {1}, Group: {2}, Genre: {3}", movie.Title,movie.Year,movie.GroupId, movie.Genre);
}
selectedMovies2.Display();
输出:
选择 1 - 标题:Movie1,2000 年,组:1,类型:动作
标题:Movie4,2000 年,组:2,类型:动作