C# 使用依赖解析程序是一种糟糕的做法吗?

C# 使用依赖解析程序是一种糟糕的做法吗?,c#,asp.net-mvc,design-patterns,dependency-injection,C#,Asp.net Mvc,Design Patterns,Dependency Injection,我将在这里举个例子来阐明我的观点。请考虑以下类别: public class MovieController : Controller { private readonly IMovieService _movieService; private readonly IUserService _userService; public MovieController(IMovieService movieService, IUserService userService)

我将在这里举个例子来阐明我的观点。请考虑以下类别:

public class MovieController : Controller
{
    private readonly IMovieService _movieService;
    private readonly IUserService _userService;

    public MovieController(IMovieService movieService, IUserService userService)
    {
        _movieService = movieService;
        _userService = userService;
    }

    public ViewModel GetMovies()
    {
        return View("Movies", _movieService.GetMovies());
    }

    public ViewModel GetAuthors()
    {
        return View("Authors", _userService.GetAuthors());
    }
}
在上面的例子中,无论何时创建MovieController,它都将创建这两个服务。每个服务都需要构造函数中的服务和存储库。所以,实际上,每次调用MovieController时,我可能都会创建一些类。出于这个原因,我希望实现延迟加载,因为我相信它将提高性能。为此,请考虑下一堂课:

public class MovieController : Controller
{
    private readonly IMovieService _movieService;
    private readonly IUserService _userService;

    private MovieService 
    {
        get 
        {
            if (_movieService == null) _movieService = new MovieService();
            return _movieService;
        }
    }

    private UserService 
    {
        get 
        {
            if (_userService == null) _userService = new UserService();
            return _userService;
        }
    }

    public MovieController() { }

    public ViewModel GetMovies()
    {
        return View("Movies", MovieService.GetMovies());
    }

    public ViewModel GetAuthors()
    {
        return View("Authors", UserService.GetAuthors());
    }
}
上面这个例子的问题是我丢失了DI。现在我理解了DI的好处,我非常希望保留它,因此,我提出了以下示例:

public class MovieController : Controller
{
    private readonly IMovieService _movieService;
    private readonly IUserService _userService;

    private MovieService 
    {
        get 
        {
            if (_movieService == null) _movieService = DependencyResolver.Current.GetService(typeof(IMovieService));
            return _movieService;
        }
    }

    private UserService 
    {
        get 
        {
            if (_userService == null) _userService = DependencyResolver.Current.GetService(typeof(IUserService));
            return _userService;
        }
    }

    public MovieController() { }

    public ViewModel GetMovies()
    {
        return View("Movies", MovieService.GetMovies());
    }

    public ViewModel GetAuthors()
    {
        return View("Authors", UserService.GetAuthors());
    }
}

我在这个问题上的第三个例子是一个坏习惯吗?若然,原因为何?这样做是否会降低性能,或者这被认为是不好的做法的另一个原因?

以这种方式使用依赖项解析程序意味着您正在使用

您是否有任何理由认为创建
MovieService
UserService
会有性能问题?您在这些类的构造函数中做了一些重要的事情吗?如果是这样,那么你可能不应该这样做。在构造函数中,您几乎应该始终只接受依赖项并将它们存储在私有字段中

如果出于某种原因,您仍然希望延迟加载,那么您可以创建如下内容:

public class LazyMovieService : IMovieService
{
    private readonly Lazy<IMovieService> lazyInstance;

    public LazyMovieService(Func<IMovieService> instanceFactory)
    {
        lazyInstance = new Lazy<IMovieService>(instanceFactory);
    }
    public string[] GetMovies()
    {
        return lazyInstance.Value.GetMovies();
    }
}

以这种方式使用依赖项解析器意味着您正在使用

您是否有任何理由认为创建
MovieService
UserService
会有性能问题?您在这些类的构造函数中做了一些重要的事情吗?如果是这样,那么你可能不应该这样做。在构造函数中,您几乎应该始终只接受依赖项并将它们存储在私有字段中

如果出于某种原因,您仍然希望延迟加载,那么您可以创建如下内容:

public class LazyMovieService : IMovieService
{
    private readonly Lazy<IMovieService> lazyInstance;

    public LazyMovieService(Func<IMovieService> instanceFactory)
    {
        lazyInstance = new Lazy<IMovieService>(instanceFactory);
    }
    public string[] GetMovies()
    {
        return lazyInstance.Value.GetMovies();
    }
}


关于第三种方法,我脑海中立刻闪现的一个问题是,我如何
unit
测试“GetMovies”,为什么你还要检查_userService/_movieService是否为空?你从不使用它们twice@Jaya我想我明白你的意思了,你是在问我如何通过一个假的DbContext而不是一个真实的DbContext。@Jaya我也可以把它注入到我的单元测试中,以确保测试是可能的。从未真正这样做过,但现在我想知道这是否是一个坏主意?@Bojan前几天看到了这篇文章,你可能会对第三种方法感兴趣。我马上想到的一个问题是,我如何
unit
测试“GetMovies”,你为什么还要检查_userService/\u movieService是否为空?你从不使用它们twice@Jaya我想我明白你的意思了,你是在问我如何通过一个假的DbContext而不是一个真实的DbContext。@Jaya我也可以把它注入到我的单元测试中,以确保测试是可能的。从未真正这样做过,但现在我想知道这是否是一个坏主意?@Bojan前几天偶然看到这篇文章,你可能会觉得很有趣,我不完全确定最后一部分是否适用于这里(合成根部分),因为它似乎是一个ASP.NET核心DI(即,你没有实例化控制器)。但我也询问了实例化services@CamiloTerevinto:它不仅不适用于此处,而且也不适用于原始mvc。你也不能自己实例化控制器。@WiktorZychla,在ASP.NET MVC中,你可以创建一个自定义的
IControllerFactory
,这就是你如何做的@CamiloTerevinto,我记得在ASP.NET内核中也有一种使用纯DI的方法。@YacoubMassad:你可以,但你并不真正需要它,只是答案的最后一部分是不必要的,剩下的没问题。你只是注入懒惰,仅此而已。我甚至不想在这里完成我自己的答案,因为你的答案涵盖了这个问题。我不完全确定最后一部分是否适用于这里(合成根部分),因为它似乎是一个ASP.NET核心DI(即,你没有实例化控制器)。但我也询问了实例化services@CamiloTerevinto:它不仅不适用于此处,而且也不适用于原始mvc。你也不能自己实例化控制器。@WiktorZychla,在ASP.NET MVC中,你可以创建一个自定义的
IControllerFactory
,这就是你如何做的@CamiloTerevinto,我记得在ASP.NET内核中也有一种使用纯DI的方法。@YacoubMassad:你可以,但你并不真正需要它,只是答案的最后一部分是不必要的,剩下的没问题。你只是注入懒惰,仅此而已。我甚至懒得在这里完成我自己的答案,因为你的答案涵盖了这个问题。