你的位置:首页 > ASP.net教程

[ASP.net教程]记录对依赖注入的小小理解和autofac的简单封装


      首先,我不是一个开发者,只是业余学习者。其次我的文化水平很低,写这个主要是记录一下当前对于这块的理解,因为对于一个低水平 的业余学习者来说,忘记是很平常的事,因为接触、应用的少,现在理解,可能过段时间就会忘了,自己记录下来应该可以少走些弯路,以免从头再来查找资料。

     另外,如果我的记录能帮忙到一些朋友的话,也难免会有些小满足的。学习的门槛除了理解能力,绝大部分来自于英文水平和专业术语,我希望的是我能用比较通俗易懂的表达,获得大家的理解,更希望大牛们是如是做的,所以写这个更希望的是能得到大牛的帮助。

     下面是我对依赖注入在应用场景的理解

     从框架设计方面 你希望的是你设计的架构能有不同的技术(或者叫第三方组件)实现,你只需要通过在固定地方修改极少的代码便可以。

     来个例子吧,假如现在有两个不同的技术,当然它们应该是在不同的程序集中的,只是为了方便把它们放在一起

  /// <summary>  /// 第三方组件A  /// </summary>  public class ModuleA   {    public void Say()    {      Console.WriteLine("it is ModuleA");    }  }  /// <summary>  /// 第三方组件B  /// </summary>  public class ModuleB   {    public void Say()    {      Console.WriteLine("it is ModuleB");    }  }

 

   你希望你能应用任意其中一个,并且可以随意更改。你可以对外抽象出一个约束接口或者抽象类,下面我用的是接口,你可以在你的设计中,通过构造函数来引用

 /// <summary>  /// 接口  /// </summary>  public interface IInterface  {    void Say();//接口约束必须实现这个方法  }  public class BaseStyle  {    private IInterface module;//你并不知道也不关心当前用的是哪个组件,只要组件能实现这个接口就行    public BaseStyle(IInterface module)//能过构造函数引用接口    {      this.module = module;    }    public void Say()    {      module.Say();    }  }

 

  通过属性引用

  /// <summary>  /// 通过属性引用组件方式  /// </summary>   public class BaseStyle  {    public IInterface Module { get; set; }    public void Say()    {      Module.Say();    }  }

  

 

当你要应用任意一个组件时,只须要让它实现接口

public class ModuleA : IInterface  {    public void Say()    {      Console.WriteLine("it is ModuleA");    }  }

  

这样就把BaseStyle类的Say方法分离出来,通过接口的实现类来完成。相当于接口的实现类可以是任意类。这便是传说中的接口分离,低藕合思想。例子不需要大,理解才是最重要。往大了说,这就相当于是面向接口编程。这是架构设计方面 。

      然后就是应用了,也就是注入工作,Autofac之类的依赖注入组件不是必须的,只是当你的程序大了,用这些封装好的组件会更方便,易维护。你可以new BaseStyle然后传入对就的参数或设置属性就行了。

      我一般用的是Autofac,用autofac,代码应该 是这样的

class Program  {    static void Main(string[] args)    {      ContainerBuilder builder = new ContainerBuilder();      builder.Register(o => new BaseStyle(o.Resolve<IInterface>()));//实例注入      builder.RegisterType<ModuleA>().As<IInterface>();       //类型注入      using (var container = builder.Build())      {        BaseStyle bs = container.Resolve<BaseStyle>();        bs.Say();      }      Console.ReadKey();    }

  当然这样用肯定是没必要用autofac的,当有很多类须要用到Autofac注入时,这样并不会减少代码量,当要修改时,每个地方都要修改,如果只对Autofac停留在这个层面,还是不必要用它的好。

     我比较喜欢的是封装一个Container类,由于我一惯喜欢用强类型,所以没有试过通过配置文件来配置。可能是因为我没有接触到真实项目的原因吧

封装一个类

 public class ServiceContainer  {    private ServiceContainer() { }//不对外提供构造函数    private static IContainer container;    /// <summary>    /// 初始化container    /// </summary>    /// <param name="action"></param>    public static void Initialize(Action<ContainerBuilder> action)    {      if(action!=null)      {        ContainerBuilder builder = new ContainerBuilder();        action(builder);        container = builder.Build();      }    }    /// <summary>    /// 封装一个不带参数的IContainer的方法    /// </summary>    /// <typeparam name="Tservice"></typeparam>    /// <returns>返回一个注入的服务类实例</returns>    public static Tservice Resolve<Tservice>()    {      ThrowIfNotInitialized();       //检测容器是否初始化      return container.Resolve<Tservice>();    }    //此处省略其它IContainer方法的封装    /// <summary>    /// 检测容器是否初始化    /// </summary>    private static void ThrowIfNotInitialized()    {      if (container == null)        throw new InvalidOperationException("请先初始化容器,调用Initialize()方法");    }  }

   通过个类提供的静态初始化方法,可以在应用程序开始处,将所有要注入的依赖注入到容器中,然后你可以在程序的任意地方通过静态方法Resolve<T>方法从容器中取得你想要的具体依赖。这里我只封装了一个方法,还可以封装更多的静态方法,灵活调用。

     最后再传上测试的所有代码。这里我抽象出了一些基类,设置好依赖注入,方便客户端调用时不需要传入参数或是设置属性,个人感觉应该比较完美了

using System;using Autofac;namespace AutofacDemo{  class Program  {    static void Main(string[] args)    {      ServiceContainer.Initialize(o =>      {        o.RegisterType<ModuleA>().As<IInterface>();        //o.RegisterType<ModuleB>().As<IInterface>();需要用其它实现时,只须要修改传入对应的类型      });      StyleA a = new StyleA();//纯净的客户端调用      StyleB b = new StyleB();      a.Say();      b.Say();      #region 基本注入      //ServiceContainer.Initialize(o =>      // {      //   o.RegisterType<ModuleA>().As<IInterface>();      // });      //StyleA a = new StyleA(ServiceContainer.Resolve<IInterface>());      //StyleB b = new StyleB();      //b.Module = ServiceContainer.Resolve<IInterface>();      //a.Say();      //b.Say();      #endregion      #region 实例注入、属性注入      //ServiceContainer.Initialize(o =>      //{      //  o.Register(c => new StyleA(c.Resolve<IInterface>()));       //实例注入      //  o.Register(c => new StyleB { Module = c.Resolve<IInterface>() });//属性注入      //  o.RegisterType<ModuleA>().As<IInterface>();      //});      //StyleA a = ServiceContainer.Resolve<StyleA>();      //StyleB b = ServiceContainer.Resolve<StyleB>();      //a.Say(); b.Say();       #endregion      Console.ReadKey();    }  }  /// <summary>  /// 接口  /// </summary>  public interface IInterface  {    void Say();  }  /// <summary>  /// 接口的某个实现类A,通常相当于第三方组件  /// </summary>  public class ModuleA : IInterface  {    public void Say()    {      Console.WriteLine("it is ModuleA");    }  }  /// <summary>  /// 接口的某个实现类B,通常相当于第三方组件  /// </summary>  public class ModuleB : IInterface  {    public void Say()    {      Console.WriteLine("it is ModuleB");    }  }  public class BaseStyle  {    private IInterface module;    public BaseStyle(IInterface module)    {      this.module = module;    }    public void Say()    {      module.Say();    }  }  /// <summary>  /// 基类通过构造函数引用组件方式  /// </summary>  public abstract class BaseStyleA  {    private IInterface module;    protected BaseStyleA(IInterface module)    {      this.module = module;    }    public void Say()    {      module.Say();    }  }  /// <summary>  /// 基类通过属性引用组件方式  /// </summary>  public abstract class BaseStyleB  {    public virtual IInterface Module { get; set; }    public void Say()    {      Module.Say();    }  }  public class StyleA:BaseStyleA  {    public StyleA(IInterface module) : base(module) { }    public StyleA() : base(ServiceContainer.Resolve<IInterface>())//方便客户端调用时不需要传参    {    }  }  public class StyleB:BaseStyleB  {    public override IInterface Module    {      get      {        return ServiceContainer.Resolve<IInterface>();//方便客户端调用时不需要设置属性      }    }  }}

View Code