控制反转(inversion of control,IOC)是设计模式中非常重要的思想,而依赖注入(dependency injection,DI)是控制反转思想的一种重要的实现方式。依赖注入简化了模块的组装过程,减小了模块之间的耦合度,因此.NET Core中大量应用了依赖注入的开发模式
控制反转的目的是将“创建和组装对象”操作的控制权从业务逻辑转移到框架中。当我们需要某个类型的对象时,由框架来提供这个对象,我们不需要关注此对象的创建过程
假设框架中有个ServiceLocator的类,通过调用GetService()就能获取我们想要的对象。至于对象创建过程我们则不需要关心
IDbConnection conn = ServiceLocator.GetService<IDbConnection>();
public class Demo
{
IDbConnection conn;
public Demo(IDbConnection conn)
{
this.conn = conn;
}
}
系统在创建Demo类时,自动为conn 赋一个合适的对象。这种框架自动创建对象的动作就叫做注入
.NET Core中内置了控制反转机制,支持依赖注入和服务定位器两种方式。由于依赖注入是推荐的方式,因此微软将内置的控制反转组件命名为DependencyInjection
依赖注入框架中注册的服务有一个重要的概念叫做“生命周期”,一共有三种
安装依赖包
Microsoft.Extensions.DependencyInjection
创建接口和实现类
public interface ITestService
{
public void Run();
}
public class TestServiceImpl : ITestService
{
public void Run()
{
Console.WriteLine("我是测试实现类");
}
}
注册服务和获取服务
ServiceCollection services = new ServiceCollection();
services.AddScoped<ITestService, TestServiceImpl>(); //true,因为在同一范围内获取对象所以为true
//services.AddSingleton<ITestService, TestServiceImpl>(); 单例,全局共享一个对象,所以返回true
//services.AddTransient<ITestService, TestServiceImpl>(); 瞬态每次获取都会创建一个新的对象,返回false
using (ServiceProvider sp = services.BuildServiceProvider())
{
ITestService service1 = sp.GetRequiredService<ITestService>();
ITestService service2 = sp.GetRequiredService<ITestService>();
Console.WriteLine(service1 == service2); //true,因为在同一范围内获取对象所以为true
Console.Read();
}
上面通过GetRequiredService方法来获取ITestServcie对象,很显然这种属于服务定位器方式
增加服务类
public interface IPayService
{
public void Pay();
}
public class PayServiceImpl : IPayService
{
public void Pay()
{
Console.WriteLine("支付了10元");
}
}
改写TestServiceImpl类
public class TestServiceImpl : ITestService
{
public IPayService PayService;
public TestServiceImpl(IPayService PayService)
{
this.PayService = PayService;
}
public void Run()
{
PayService.Pay();
}
}
注册服务和运行
ServiceCollection services = new ServiceCollection();
services.AddScoped<ITestService, TestServiceImpl>();
services.AddScoped<IPayService, PayServiceImpl>();
using (ServiceProvider sp = services.BuildServiceProvider())
{
ITestService service = sp.GetRequiredService<ITestService>();
service.Run();
}
输出结果:支付了10元
不要在长生命周期的对象中引用比它短的生命周期的对象。比如不能在单例服务中引用范围服务,否则可能会导致被引用的对象已经释放或者导致内存泄漏
我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
我今天看到了一个ruby代码片段。[1,2,3,4,5,6,7].inject(:+)=>28[1,2,3,4,5,6,7].inject(:*)=>5040这里的注入(inject)和之前看到的完全不一样,比如[1,2,3,4,5,6,7].inject{|sum,x|sum+x}请解释一下它是如何工作的? 最佳答案 没有魔法,符号(方法)只是可能的参数之一。这是来自文档:#enum.inject(initial,sym)=>obj#enum.inject(sym)=>obj#enum.inject(initial){|mem
有什么方法可以告诉sidekiq一项工作依赖于另一项工作,并且在后者完成之前无法开始? 最佳答案 仅使用Sidekiq;答案是否定的。正如DickieBoy所建议的那样,您应该能够在依赖作业完成时将其启动。像这样。#app/workers/hard_worker.rbclassHardWorkerincludeSidekiq::Workerdefperform()puts'Doinghardwork'LazyWorker.perform_async()endend#app/workers/lazy_worker.rbclassLaz
Ruby中防止SQL注入(inject)的好方法是什么? 最佳答案 直接使用ruby?使用准备好的语句:require'mysql'db=Mysql.new('localhost','user','password','database')statement=db.prepare"SELECT*FROMtableWHEREfield=?"statement.execute'value'statement.fetchstatement.close 关于ruby-防止SQL注入(inject
目录一.大致如下常见问题:(1)找不到程序所依赖的Qt库version`Qt_5'notfound(requiredby(2)CouldnotLoadtheQtplatformplugin"xcb"in""eventhoughitwasfound(3)打包到在不同的linux系统下,或者打包到高版本的相同系统下,运行程序时,直接提示段错误即segmentationfault,或者Illegalinstruction(coredumped)非法指令(4)ldd应用程序或者库,查看运行所依赖的库时,直接报段错误二.问题逐个分析,得出解决方法:(1)找不到程序所依赖的Qt库version`Qt_5'
在此处阅读有关SO的各种解释,它们是这样描述的:map:Themapmethodtakesanenumerableobjectandablock,andrunstheblockforeachelement注入(inject):Injecttakesavalueandablock,anditrunsthatblockonceforeachelementofthelist.希望你明白为什么我觉得它们表面上看起来很相似。我什么时候会选择一个而不是另一个,它们之间有什么明显的区别吗? 最佳答案 如果您认为inject也别名为reduce,这
为什么下面的代码会报错?['hello','stack','overflow'].inject{|memo,s|memo+s.length}TypeError:can'tconvertFixnumintoStringfrom(irb):2:in`+'from(irb):2:in`blockinirb_binding'from(irb):2:in`each'from(irb):2:in`inject'from(irb):2如果传递了初始值,它就可以正常工作:['hello','stack','overflow'].inject(0){|memo,s|memo+s.length}=>18
代码:threads=[]Thread.abort_on_exception=truebegin#throwexceptionsinthreadssowecanseethemthreadseputs"EXCEPTION:#{e.inspect}"puts"MESSAGE:#{e.message}"end崩溃:.rvm/gems/ruby-2.1.3@req/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:478:inload_missing_constant':自动加载常量MyClass时检测到循环依赖稍加研究后,
我在目录“/home/enterprise/pkg”中有一个本地gem(enterprise-0.0.1.gem)。它依赖于active_directorygem(v1.5.5),这是在它的enterprise.gemspec文件中指定的,如下所示:-gem.add_dependency("active_directory")在我的应用程序的Gemfile中,我添加了以下行:-gem'enterprise','0.0.1',path=>'/home/enterprise/pkg'当我做的时候bundleinstall在我的应用程序的源目录中,只安装了企业gem。因此,我遇到了引用act