C#方法不返回对象 - 方法链接

时间:2017-04-02 20:27:03

标签: c# methods chaining

我遇到了stackoverflow上的帖子,通过链接两个方法提供问题的解决方案。答案看起来像这样:

public x DoThis()
 {
    //do something
    return this; 

 }

public x DoThat ()
{
   //do something else
   return this;

}

var x = new x ().DoThis().DoThat;

我读到了链接方法。但在这种情况下,某些事情似乎并不正确。我创建了一个名为Library的类,它有两个返回相同类型的不同方法,我可以访问第一个方法,但不能访问第二个方法。除非,我做错了,解决方案不正确。

我观看了有关创建集合扩展方法的教程,我想尝试使用这种方法。我不得不承认我还不了解它的一切。所以我想,我应该可以使用IEnumerable<>因为我只是将集合传递给这个班级

这是一个班级:

class Library
{
    private IEnumerable<Movie> MoviesLibrary;


    public Library(IEnumerable<Movie> library)
    {
        this.MoviesLibrary = library.ToList();

    }

    public IEnumerable<Movie> FindMovie(int _movieId)
    {


        return this.MoviesLibrary.Where(movie => movie.MovieId == _movieId);


    }

    public IEnumerable<Movie> GetByYear(int _year)
    {

        return this.MoviesLibrary.Where(movie => movie.Year == _year);

    }

}

据我所知,“return this”语句应该返回当前实例化的对象。在链式方法中,下一个方法应该使用返回的对象并执行自己的操作。

2 个答案:

答案 0 :(得分:0)

您能为您提供的第一个代码示例提供更多上下文吗? (那个不起作用的那个 - 例如在你的情况下什么是X?什么类有第一种方法?)。

你给出的最后一个例子

public IEnumerable<Movie> GetByYear(int _year)
{
   this.MoviesLibrary.Where(movie => movie.MovieId == _movieId);
    return this;
}

不正确,因为你返回一个IEnumerable, 并且IEnumerable没有不是扩展方法的附加方法。

扩展方法确实可以帮助您实现您想要的目标。 实际上,Linq是作为IEnumerable

的一组扩展方法实现的

请参阅 https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,577032c8811e20d3

了解更多信息(以及如何编写扩展方法的示例)。

另外,您可能希望在其正式的msdn页面中阅读有关扩展方法的更多信息 https://msdn.microsoft.com/en-us/library/bb383977.aspx

答案 1 :(得分:0)

这是我自己的问题的解决方案。我必须承认,从一开始就不清楚我想要完成什么,这在初始帖子的编辑中很明显。第一个代码示例是对此站点上其他人发布的类似问题的回答。它本质上是非常通用的,但是你可以清楚地看到这个人试图提倡通过返回相同的对象类型链接方法是可能的。在看了Zoran Horvat的“让你的C#代码更加面向对象”的教程之后,我想完成类似的事情。 Pluralsight上提供了本教程。他的例子是在第4章和第5章中使用接口和扩展方法。这个解决方案的想法有些类似,但我希望将这个功能包含在一个类中。

我认为整个混淆与方法需要返回以提供链接功能的对象类型有关。我们来看一些简单的字符串示例

someString.ToUpper.ToLower.Trim

我们首先想到的是,字符串从一个方法传递到另一个方法,并且每个步骤都由该方法修改。因此,在处理集合时我们会遇到类似的情况。

movies.GetByYear(1999).GetByGroup(1).GetByGenre(&#34;动作&#34)

在这种情况下,我们从一些通过这个方法链传递的List开始。我们也很可能认为该链中的所有方法都在同一个List上运行。毕竟,前一个示例中的字符串属性在所有方法之间共享,即使它正在被修改。这不是这部电影真正发生的事情。每种方法都适用于具有不同大小的集合。看起来像GetByYear()和GetByGroup()是使用相同电影列表的方法,它们实际上是具有完全不同列表的独立库对象。

我要感谢Sokohavi留下关于返回Library对象的评论。他还建议使Library对象IEnumerable。不幸的是,如果你认为该方法应该返回IEnumerable,那么你的路径就错了。从技术上讲,Library是一个List,但保存Movie对象的列表设置为private,对其他对象不可见。因此没有什么可以迭代的。库对象只有几个方法,如果您选择其中一个方法,您将无法访问同一个类中的其他方法。因此,方法必须返回Library对象才能访问同一类中的所有方法,并且存储Movie对象的列表必须是IEnumerable。这种方法有一个缺点。您无法将数据加载到Library构造函数中的此列表中。而是将数据作为参数传递。现在你有了具有不同电影列表的对象,以及它们彼此通信的方式是通过它们的构造函数。

下面我们有Repository类,它通过构造函数将各个项加载到列表中。 Library类定义了一些方法,这些方法将提供对传递给它的列表的过滤。您还可以创建另一个使用该功能的抽象层。

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,类型:动作