Seb*_*cia 8 c# dependency-injection inversion-of-control autofac
我是新用的Autofac,所以我为noob问题道歉.我阅读了互联网上的每本手册,解释了使用Autofac(或任何其他工具,如Structuremap,Unity等)时的基本知识.但我发现的所有例子都是基础知识.我需要知道如何在我的代码中更深入地实现Autofac.让我试着解释一下我需要知道的这个例子,一个控制台应用程序.
class Program
{
static void Main(string[] args)
{
var container = BuildContainer();
var employeeService = container.Resolve<EmployeeService>();
Employee employee = new Employee
{
EmployeeId = 1,
FirstName = "Peter",
LastName = "Parker",
Designation = "Photographer"
};
employeeService.Print(employee);
}
static IContainer BuildContainer()
{
var builder = new ContainerBuilder();
builder.RegisterType<EmployeeRepository>().As<IEmployeeRepository>();
builder.RegisterType<EmployeeService>();
return builder.Build();
}
}
Run Code Online (Sandbox Code Playgroud)
这很简单.我想弄清楚的是当你深入研究代码时如何实现这一点.在此示例中,执行此行时
employeeService.Print(employee);
Run Code Online (Sandbox Code Playgroud)
让我们假设"Print"方法有点复杂,需要使用其他依赖项/类来完成他的任务.我们仍在使用Autofac,所以我想我们需要像上面的例子那样创建依赖项.那是对的吗?在我的"print"方法中,当我需要使用另一个类时,我必须创建另一个容器,填充它,与Resolve()一起使用它等等?有一种更简单的方法吗?在所有解决方案中都可以使用具有所需所有依赖关系的静态类?怎么样?我希望能够清楚.也许我无法表达我的需要.:(抱歉我的英语很差.我在学习Autofac时仍在学习它.
Joh*_* Wu 27
控制台程序的主要问题是主Program
类主要是静态的.这不适合单元测试,对IoC也不好; 例如,永远不会构造静态类,因此没有构造函数注入的机会.结果,您最终new
在主代码库中使用,或从IoC容器中提取实例,这违反了模式(此时更多的是服务定位器模式).我们可以通过回到将代码放在实例方法中的实践来摆脱这种混乱,这意味着我们需要一个对象实例.但是什么东西?
在编写控制台应用程序时,我遵循特定的轻量级模式.欢迎您遵循这种模式,这对我来说非常有用.
该模式涉及两个类:
Program
类,它是静态的,非常简短,并且从代码覆盖范围中排除.此类充当从O/S调用到适当调用应用程序的"传递".Application
类,完全注入并可单元测试.这是您的真实代码应该存在的地方.O/S需要一个Main
入口点,它必须是静态的.该Program
班的存在只是为了满足这一要求.
保持静态程序非常干净; 它应该包含(1)组合根和(2)一个简单的"传递"入口点,它调用真实的应用程序(正如我们将看到的那样是实例化的).
所有代码Program
都不值得进行单元测试,因为它所做的只是组成对象图(无论如何在测试中都会有所不同)并调用应用程序的主入口点.通过隔离非单元可测试代码,您现在可以从代码覆盖中排除整个类(使用ExcludeFromCodeCoverageAttribute).
这是一个例子:
[ExcludeFromCodeCoverage]
static class Program
{
private static IContainer CompositionRoot()
{
var builder = new ContainerBuilder();
builder.RegisterType<Application>();
builder.RegisterType<EmployeeService>().As<IEmployeeService>();
builder.RegisterType<PrintService>().As<IPrintService>();
return builder.Build();
}
public static void Main() //Main entry point
{
CompositionRoot().Resolve<Application>().Run();
}
}
Run Code Online (Sandbox Code Playgroud)
如你所见,非常简单.
现在实现你的Application
课程,好像它是独一无二的程序.只有现在,因为它是实例化的,你可以按照通常的模式注入依赖项.
class Application
{
protected readonly IEmployeeService _employeeService;
protected readonly IPrintService _printService;
public Application(IEmployeeService employeeService, IPrintService printService)
{
_employeeService = employeeService; //Injected
_printService = printService; //Injected
}
public void Run()
{
var employee = _employeeService.GetEmployee();
_printService.Print(employee);
}
}
Run Code Online (Sandbox Code Playgroud)
这种方法可以分离关注点,避免过多的静态"东西",让您无需太多麻烦就可以遵循IoC模式.你会注意到 - new
除了实例化一个ContainerBuilder之外,我的代码示例不包含关键字的单个实例.
因为我们遵循这种模式,如果PrintService
或EmployeeService
拥有自己的依赖关系,容器现在将处理所有这些.只要您在组合根中的相应接口下注册它们,就不必实例化或编写任何代码来获取注入的服务.
class EmployeeService : IEmployeeService
{
protected readonly IPrintService _printService;
public EmployeeService(IPrintService printService)
{
_printService = printService; //injected
}
public void Print(Employee employee)
{
_printService.Print(employee.ToString());
}
}
Run Code Online (Sandbox Code Playgroud)
这样容器可以处理所有事情,您不必编写任何代码,只需注册您的类型和接口即可.