C#方法没有返回对象 - 方法链

问题描述:

我碰到计算器上后,所提供的解决方案通过链接两种方法来质疑。答案看起来像这样:C#方法没有返回对象 - 方法链

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

} 

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

} 

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

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

我看了创建收集extention方法教程,我想尝试使用这种方法。我不得不承认我还没有完全了解它的一切。所以我想,我应该能够使用的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); 

    } 

} 

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

+2

你明白什么['this'](https://msdn.microsoft.com/zh-cn/library/dk1507sz.a spx)是? –

+0

问题很混乱,但它听起来像你想要的“方法链” - http://stackoverflow.com/questions/1119799/method-chaining-in-c-sharp –

+0

我编辑了我的初始帖子 – tipitoe

你能为你提供了第一个代码示例更多的环境? (不起作用的例子 - 例如你的情况是什么,X是什么类,第一种方法?)。

的最后一个例子,你给了,因为你返回一个IEnumerable, 和IEnumerable没有额外的方法,不扩展方法

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

不正确。

扩展方法确实可以帮助你实现你想要的。 事实上,LINQ的实现为一组扩展方法的IEnumerable

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

更多信息(和示例如何编写扩展方法)。你

可能还需要在其正式MSDN页面 https://msdn.microsoft.com/en-us/library/bb383977.aspx

+0

我编辑了我的初始文章 – tipitoe

+0

我认为你错过了一些知识(没关系) - 我可以给你一个简短的答案,但要了解基本的语言,你将不得不深入研究一些文档(简而言之,c#是最好的我为c#阅读的书)......不用担心:)但是从你编辑的文章中,我认为最好先阅读关于语言的基础知识....目前,'Library'示例不会甚至编译 - 为了编译它必须实现IEnumerable ...只有当方法的返回类型也是Library和Library是IEnumerable时,你想要的链才能工作。 – sokohavi

+0

我编辑的最后一个方法,他们都返回相同的类型IEnumerable tipitoe

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

我认为整个混乱涉及该方法需要以提供链接功能返回对象的类型。让我们来看看一些简单的字符串例子

someString.ToUpper.ToLower。修剪

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

movies.GetByYear(1999).GetByGroup(1).GetByGenre( “行动”)

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

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

下面我们有一个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 - 标题:剧场1,2000年,集团:1,游戏类型:动作

标题:Movie4 ,2000年,组:2,类型:动作