Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 是否将类型返回为IEnumerable而不仅仅是List?_C#_Asp.net Mvc_Ienumerable - Fatal编程技术网

C# 是否将类型返回为IEnumerable而不仅仅是List?

C# 是否将类型返回为IEnumerable而不仅仅是List?,c#,asp.net-mvc,ienumerable,C#,Asp.net Mvc,Ienumerable,我正在做一个.NETMVC教程。话虽如此,我还是遇到了这样的代码: public class MoviesController : Controller { public ActionResult Index() { var movies = GetMovies(); return View(movies); } private IEnumerable<Movie> GetMovies() {

我正在做一个.NETMVC教程。话虽如此,我还是遇到了这样的代码:

public class MoviesController : Controller
{
    public ActionResult Index()
    {
        var movies = GetMovies();

        return View(movies);
    }

    private IEnumerable<Movie> GetMovies()
    {
        return new List<Movie>
        {
            new Movie {Id = 1, Name = "Shrek"},
            new Movie {Id = 2, Name = "LotR"}
        };
    }
}
电影的索引视图如下所示:

@model IEnumerable<VideoStore.Models.Movie>

@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Movies</h2>
<table class="table table-bordered table-hover">
    <thead>
        <tr>
            <th>Movie</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var movie in Model)
        {
            <tr>
                <td>@movie.Name</td>
            </tr>
        }
    </tbody>
</table>

所以我的问题是,为什么在私有方法GetMovies中的MoviesController中使用IEnumerable返回类型?为什么不使用列表返回类型?

IEnumerable是接口,因此它更灵活,如果使用列表,则强制接收方法使用列表

IEnumerable是一个接口,所以它更灵活,如果使用List,则强制接收方法使用expect List

IEnumerable是与遍历列表相关的接口。返回列表将立即向GetMovies的使用者公开比严格必要的更多的操作,例如从集合中添加或删除操作,这会更容易引入错误。在技术上没有理由选择IEnumerable而不是List,因为在引擎盖下它的行为是相同的。这个决定纯粹是实用的。

IEnumerable是与迭代列表相关的接口。返回列表将立即向GetMovies的使用者公开比严格必要的更多的操作,例如从集合中添加或删除操作,这会更容易引入错误。在技术上没有理由选择IEnumerable而不是List,因为在引擎盖下它的行为是相同的。这个决定纯粹是实用的。

我无法解释开发人员在特定代码背后的确切推理,但一般来说,我们使用最通用的可接受类型,通常是用于输入的接口,就像在视图中所做的那样。这允许我们从不同的资源中获取数据并在它们之间切换


至于返回输出,返回泛型接口而不是实际类型没有任何好处,除非函数根据某些条件返回不同的子类型,在您的示例中并非如此。或者,如果类本身正在实现一个接口,那么出于上述相同的原因,接口返回最通用的可接受类型是很有用的。这也不是您的情况,因此在您的情况下,返回IEnumerable没有任何好处。

我无法解释开发人员在特定代码背后的确切推理,但一般来说,我们使用最通用的可接受类型,通常是一个输入接口,就像在视图中所做的那样。这允许我们从不同的资源中获取数据并在它们之间切换


至于返回输出,返回泛型接口而不是实际类型没有任何好处,除非函数根据某些条件返回不同的子类型,在您的示例中并非如此。或者,如果类本身正在实现一个接口,那么出于上述相同的原因,接口返回最通用的可接受类型是很有用的。这也不是您的情况,因此在您的情况下,返回IEnumerable没有任何好处。

使用IEnumerable会削弱耦合,这允许它在实现更改时与其他具体类型向前兼容。在不更改界面的情况下,可以进行以下所有更改:

//Original
private IEnumerable<Movie> GetMovies()
{
    return new List<Movie>
    {
        new Movie {Id = 1, Name = "Shrek"},
        new Movie {Id = 2, Name = "LotR"}
    };
}

//Using an array
private IEnumerable<Movie> GetMovies()
{
    return new Movie[]
    {
        new Movie {Id = 1, Name = "Shrek"},
        new Movie {Id = 2, Name = "LotR"}
    };
}

//From EF
private IEnumerable<Movie> GetMovies()
{
    return dbContext.Movies.Where( m => Name == "Shrek" || Name == "Lotr );
}


//Covariant
class NerdMovie : Movie {}

private IEnumerable<Movie> GetMovies()
{
    return new List<NerdMovie>
    {
        new NerdMovie {Id = 1, Name = "Shrek"},
        new NerdMovie {Id = 2, Name = "LotR"}
    };
}


//Custom type
class MovieList : List<Movie> { }

private IEnumerable<Movie> GetMovies()
{
    return new MovieList
    {
        new Movie {Id = 1, Name = "Shrek"},
        new Movie {Id = 2, Name = "LotR"}
    };
}

//Using yield
private IEnumerable<Movie> GetMovies()
{
    yield return new Movie {Id = 1, Name = "Shrek"};
    yield return new Movie {Id = 2, Name = "LotR"};
}

使用IEnumerable会削弱耦合,这允许它在实现发生更改时与其他具体类型向前兼容。在不更改界面的情况下,可以进行以下所有更改:

//Original
private IEnumerable<Movie> GetMovies()
{
    return new List<Movie>
    {
        new Movie {Id = 1, Name = "Shrek"},
        new Movie {Id = 2, Name = "LotR"}
    };
}

//Using an array
private IEnumerable<Movie> GetMovies()
{
    return new Movie[]
    {
        new Movie {Id = 1, Name = "Shrek"},
        new Movie {Id = 2, Name = "LotR"}
    };
}

//From EF
private IEnumerable<Movie> GetMovies()
{
    return dbContext.Movies.Where( m => Name == "Shrek" || Name == "Lotr );
}


//Covariant
class NerdMovie : Movie {}

private IEnumerable<Movie> GetMovies()
{
    return new List<NerdMovie>
    {
        new NerdMovie {Id = 1, Name = "Shrek"},
        new NerdMovie {Id = 2, Name = "LotR"}
    };
}


//Custom type
class MovieList : List<Movie> { }

private IEnumerable<Movie> GetMovies()
{
    return new MovieList
    {
        new Movie {Id = 1, Name = "Shrek"},
        new Movie {Id = 2, Name = "LotR"}
    };
}

//Using yield
private IEnumerable<Movie> GetMovies()
{
    yield return new Movie {Id = 1, Name = "Shrek"};
    yield return new Movie {Id = 2, Name = "LotR"};
}
是否将类型返回为IEnumerable而不仅仅是List

可改为:

public class MoviesController : Controller
{
    private readonly IMovieDb _movieDb;
    // Dependency Injecting access to movies
    public MoviesController(IMovieDb movieDb)
    {
        _movieDb = movieDb;
    }

    public ActionResult Index()
    {
        var movies = _movieDb .GetMovies();

        return View(movies);
    }
    // ....


public interface IMovieDb
{
    IEnumerable<Movie> GetMovies();
}
现在我们不知道这些电影是如何取回的。。。只要合同/接口满足我们的数据需求,我们就不应该在意

是否将类型返回为IEnumerable而不仅仅是List

可改为:

public class MoviesController : Controller
{
    private readonly IMovieDb _movieDb;
    // Dependency Injecting access to movies
    public MoviesController(IMovieDb movieDb)
    {
        _movieDb = movieDb;
    }

    public ActionResult Index()
    {
        var movies = _movieDb .GetMovies();

        return View(movies);
    }
    // ....


public interface IMovieDb
{
    IEnumerable<Movie> GetMovies();
}

现在我们不知道这些电影是如何取回的。。。只要契约/接口满足我们的数据需求,我们就不必在意。

这样,您可以将其更改为返回数组或任何实现IEnumerable的内容,而不必更改使用它的代码。基本上,您只需公开具有所需功能的最小派生类型,这样您就可以更改它以返回数组或实现IEnumerable的任何内容,而无需更改使用它的代码。基本上,您只需公开具有所有所需功能的最小派生类型。谢谢,我给您+,但Luke Samuel的答案更复杂,所以我将标记他的答案。这是错误的。您完全可以将列表返回到需要IEnumerable的视图中。谢谢@RacilHilan的说明。@RacilHilan:需要数组的方法如何?我不明白您的问题。怎么样?评论不是提问和回答问题的好地方。如果你想让我们给你一个好的答案,你可以发布一个带有代码的问题。或者至少解释一下你所说的期望数组的方法是什么意思。谢谢,我给你+,但Luke Samuel的答案更复杂,所以我会标记他的答案。这是错误的。您完全可以返回一个列表

对于需要IEnumerable的视图。谢谢@RacilHilan的澄清。@RacilHilan:需要数组的方法如何?我不明白你的问题。怎么样?评论不是提问和回答问题的好地方。如果你想让我们给你一个好的答案,你可以发布一个带有代码的问题。或者至少解释一下你所说的一个需要数组的方法是什么意思。这只适用于接收端,即视图,而不是给出端,即GetMovies函数。您可以将List从函数返回到需要IEnumerable的视图,并且仍然具有完全相同的解耦。更多细节见我的答案。我不同意;这与脱钩并不完全相同。通过在方法定义中公开列表,服务承诺提供一个列表,该列表可能非常重要,例如,如果该方法是接口或契约的一部分,并且存在向前兼容性的要求。有时明智的做法是只做你需要做的承诺,而不做更多。谢谢你的反馈。是的,这正是我在回答中解释的。但对于问题中的代码,这些条件都不适用。类没有实现接口,函数返回一个列表。在这种特定情况下,将接口用作返回类型绝对没有好处,并且它不会以任何方式改变耦合/解耦。对我来说,令人困惑的是您讨论与所讨论的代码相关的耦合的方式。耦合是一个扩展到所讨论的代码之外的概念,因为它与一件事情的更改是否需要另一件事情的更改有关。在我的回答中,我展示了六种方法来更改方法,如果您使用具体类型,那么也需要更改调用代码。所以说耦合没有区别是不正确的。仔细阅读问题。OP没有询问调用代码,即视图。类型在那里定义为IEnumerable,因此它将接受答案中的所有这些方法。OP询问了GetMovies函数返回的类型。我是说在问题中的特定代码中,将返回类型从IEnumerable更改为List不会以任何方式影响耦合。视图仍然接受IEnumerable,您的所有函数都将使用它。函数返回类型唯一起作用的是函数是否正在实现接口。这仅在接收端(即视图)正确,而在给出端(即GetMovies函数)正确。您可以将List从函数返回到需要IEnumerable的视图,并且仍然具有完全相同的解耦。更多细节见我的答案。我不同意;这与脱钩并不完全相同。通过在方法定义中公开列表,服务承诺提供一个列表,该列表可能非常重要,例如,如果该方法是接口或契约的一部分,并且存在向前兼容性的要求。有时明智的做法是只做你需要做的承诺,而不做更多。谢谢你的反馈。是的,这正是我在回答中解释的。但对于问题中的代码,这些条件都不适用。类没有实现接口,函数返回一个列表。在这种特定情况下,将接口用作返回类型绝对没有好处,并且它不会以任何方式改变耦合/解耦。对我来说,令人困惑的是您讨论与所讨论的代码相关的耦合的方式。耦合是一个扩展到所讨论的代码之外的概念,因为它与一件事情的更改是否需要另一件事情的更改有关。在我的回答中,我展示了六种方法来更改方法,如果您使用具体类型,那么也需要更改调用代码。所以说耦合没有区别是不正确的。仔细阅读问题。OP没有询问调用代码,即视图。类型在那里定义为IEnumerable,因此它将接受答案中的所有这些方法。OP询问了GetMovies函数返回的类型。我是说在问题中的特定代码中,将返回类型从IEnumerable更改为List不会以任何方式影响耦合。视图仍然接受IEnumerable,您的所有函数都将使用它。函数返回类型唯一起作用的是函数是否实现了一个接口。哇,谢谢Racil对我的问题的回答。你给了我一个很好的知识!顺便说一句,使用IEnumerable并不能加快应用程序的速度,是不是我在想这可能是原因?不是,即使返回类型是IEnumerable,代码仍然返回一个列表。唯一的区别是使用者只能看到IEnumerable公开的方法,直到它被转换到另一个类型。而不是返回它,
不。在视图中,通过IEnumerable循环的速度或快或慢可能有所不同,这取决于它是如何完成的。但是返回列表而不是IEnumerable不会以任何可测量的方式影响性能。哇,谢谢Racil对我问题的回答。你给了我一个很好的知识!顺便说一句,使用IEnumerable并不能加快应用程序的速度,是不是我在想这可能是原因?不是,即使返回类型是IEnumerable,代码仍然返回一个列表。唯一的区别是,消费者只能看到IEnumerable公开的方法,直到它被强制转换为另一种类型。不是为了返回它,不是。在视图中,通过IEnumerable的循环可能会更快或更慢,这取决于它是如何完成的。但是返回列表而不是IEnumerable不会以任何可测量的方式影响性能。哇,在这个答案上花费了很多精力。在上一个示例中,您注入了movieDb,但随后使用了iocDA。打字错误?这是很多信息@Erik,非常感谢你的努力!我以后一定会再次回到你的答案,把它作为知识的源泉。现在,你的回答&拉西尔的回答对这个问题做出了巨大的澄清!哇,在这个答案上花了很多精力。在上一个示例中,您注入了movieDb,但随后使用了iocDA。打字错误?这是很多信息@Erik,非常感谢你的努力!我以后一定会再次回到你的答案,把它作为知识的源泉。现在,你的回答&拉西尔的回答对这个问题做出了巨大的澄清!
    public ActionResult Index()
    {
        var movies = GetMovies();

        return View(movies);
    }

    private IEnumerable<Movie> GetMovies()
    {
        return new List<Movie>
        {
            new Movie {Id = 1, Name = "Shrek"},
            new Movie {Id = 2, Name = "LotR"}
        };
    }
public class MoviesController : Controller
{
    private readonly IMovieDb _movieDb;
    // Dependency Injecting access to movies
    public MoviesController(IMovieDb movieDb)
    {
        _movieDb = movieDb;
    }

    public ActionResult Index()
    {
        var movies = _movieDb .GetMovies();

        return View(movies);
    }
    // ....


public interface IMovieDb
{
    IEnumerable<Movie> GetMovies();
}