有关依赖注入的原理这里就不说了,依赖注入的框架比较多,比如:Castle、Unity、Ninject、Autofac、StructureMap、Spring.Net等。最近在项目中使用了Autofac,借此机会进行一些总结,也顺便跟大家讨论一下。Autofac主要用了Autofac.dll,AutoMapper.dll。
举个简单的例子,有一个应用用的数据库是Sql Server,将来不排除要使用Oracle或者是其它数据库。那么我们在开发的时候就要考虑了,将来要换数据库的时候是不是要重新开发?一般我们的做法是,将跟数据库交互的放在接口里,然后用Sql Server、Oracle的相关类去实现该接口,在程序初始化的时候根据数据库去实例化相应的接口。直接贴上代码:
IDatabase接口
public interface IDatabase { string Name { get; } void Select(string commandText); void Insert(string commandText); void Update(string commandText); void Delete(string commandText); }
SqlDatabase类
public class SqlDatabase : IDatabase { public string Name { get { return "sqlserver"; } } public void Select(string commandText) { Console.WriteLine(string.Format("'{0}' is a query sql in {1}!", commandText, Name)); } public void Insert(string commandText) { Console.WriteLine(string.Format("'{0}' is a insert sql in {1}!", commandText, Name)); } public void Update(string commandText) { Console.WriteLine(string.Format("'{0}' is a update sql in {1}!", commandText, Name)); } public void Delete(string commandText) { Console.WriteLine(string.Format("'{0}' is a delete sql in {1}!", commandText, Name)); } }
OracleDatabase类
public class OracleDatabase : IDatabase { public string Name { get { return "oracle"; } } public void Select(string commandText) { Console.WriteLine(string.Format("'{0}' is a query sql in {1}!", commandText, Name)); } public void Insert(string commandText) { Console.WriteLine(string.Format("'{0}' is a insert sql in {1}!", commandText, Name)); } public void Update(string commandText) { Console.WriteLine(string.Format("'{0}' is a update sql in {1}!", commandText, Name)); } public void Delete(string commandText) { Console.WriteLine(string.Format("'{0}' is a delete sql in {1}!", commandText, Name)); } }
在这里,还新增了DataBase的管理类,避免客户端直接操作IDatabase的实现类。
public class DatabaseManager { IDatabase _database; public DatabaseManager(IDatabase database) { _database = database; } public void Search(string commandText) { _database.Select(commandText); } public void Add(string commandText) { _database.Insert(commandText); } public void Save(string commandText) { _database.Update(commandText); } public void Remove(string commandText) { _database.Delete(commandText); } }
下面,我们来看Autofac的使用:
var builder = new ContainerBuilder(); builder.RegisterType<DatabaseManager>(); //builder.RegisterType<SqlDatabase>().As<IDatabase>(); builder.RegisterType<OracleDatabase>().As<IDatabase>(); using (var container = builder.Build()) { var manager = container.Resolve<DatabaseManager>(); manager.Search("SELECT * FORM USER"); }
如果要用Sql Server数据库,则将builder.RegisterType<OracleDatabase>().As<IDatabase>()改为builder.RegisterType<SqlDatabase>().As<IDatabase>()即可,其它都不变。
不过,有人会问,我直接new一个对象不是更简单么?确实,如果只有一个实现类,用new可能会更简单。但是,一个应用通常会有很多的实现类,如果都用new的话,无疑增加了维护的困难。
我不修改代码可以吗?答案是可以的。你可以通过配置文件来配置,下面增加一个配置:
<configSections> <section name="autofac" type="Autofac.Configuration.SectionHandler, Autofac.Configuration"/> </configSections> <autofac defaultAssembly="AutofacDemo"> <components> <component type="AutofacDemo.SqlDatabase, AutofacDemo" service="AutofacDemo.IDatabase"/> </components> </autofac>
客户端实现的代码如下:
var builder = new ContainerBuilder(); builder.RegisterType<DatabaseManager>(); builder.RegisterModule(new ConfigurationSettingsReader("autofac")); using (var container = builder.Build()) { var manager = container.Resolve<DatabaseManager>(); manager.Search("SELECT * FORM USER"); }
同样可以得到相同的结果。
这只是Autofac的简单使用。一个应用会有成千上万个实现类,如果每次使用时都是先注册再获取实现类的话,那用依赖注入就没多大意义了。其实,我们可以做一个公共组件,在程序初始化的时候注册,需要用的时候再获取出来,这样就很方便了。
程序初始化时调用EngineContext.Initialize(false)即可,接下来就可以直接像EngineContext.Current.Resolve<IDatabase>()这样使用了。
https://files.cnblogs.com/files/dengwenbo/AutofacInfrastructure.rar