依赖注入容器Unity Application Block快速入门(整理更新版,非原创)

概述

  Unity 应用程序块(Unity)是一个轻量级、可扩展的依赖注入容器,支持构造函数、属性和方法调用注入。它为开发人员提供了如下好处:

简化了对象的创建,尤其是分层的对象结构和依赖。

允许开发人员在运行时或者配置中指定依赖的需求抽象,以及简化了横切关注点的管理。

服务定位功能允许客户代码保存或者缓存容器。这在开发人员可以持久化容器到 ASP.NET Session 或者 Application 中的 ASP.NET Web 应用程序中特别有用。

常见场景

  除了单独解决横切关注点如日志、认证、授权、缓存和异常处理的组件以外,现代业务系统通常由定制的业务对象和在应用程序中完成特殊的或者一般的任务的组件组成。

成功构建这样的应用程序的关键是获得解耦的或者极度松耦合的设计。松耦合的应用程序更加灵活、更加易于维护。同时在开发期间进行测试,可以模拟对象的桩(轻量级模拟的实现),这增强了实质的依赖。例如,数据库连接、网络连接、ERP 连接和富用户接口组件。

依赖注入是一种用于构建松耦合应用程序的主要技术。它提供了处理对象间依赖的方法。例如,一个处理用户信息的对象可能依赖于访问数据存储验证信息和检查用户是否被授权执行更新的其他对象。依赖注入技术可以确保用户类正确的初始化及组装所有这些对象,特别是依赖是抽象的地方。

使用容器可以有很多好处,但它会改变应用程序的设计方式,尤其适合于基于组件的开发,朋友们可以有选择的使用它

 

准备相关代码

为了接下来的说明,我们先编写几个后面需要的接口和类:

接口ILogger

public interface ILogger
{
    void Write(string message);
}

 

FlatFileLogger类

public class FlatFileLogger : ILogger
{
    public void Write(string message)
    {
        Console.WriteLine(String.Format("Message:{0}", message));
        Console.WriteLine("Target:FlatFile");
    }
}

DatabaseLogger类

public class DatabaseLogger : ILogger
{
    public void Write(string message)
    {
        Console.WriteLine(String.Format("Message:{0}",message));
        Console.WriteLine("Target:Database");
    }
}

 

创建容器

在Unity中创建容器实例有两种方法,一是直接使用构造函数创建,如下代码所示:

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();
    }
}

 

第二种通过父容器创建容器,在Unity中提供了层级容器的创建,即可以通过父容器来逐级创建容器:

 

 

通过父容器来创建容器可以使用CreateChildContainer:

class Program
{
    static void Main(string[] args)
    {
        UnityContainer parentContainer = new UnityContainer();

        UnityContainer childContainer = (UnityContainer )parentContainer.CreateChildContainer();
    }
}
采用层级容器的好处是我们可以对于有不同生命周期的对象放在不同的容器中,如果一个子容器被释放,不会影响到其它子容器中的对象,但是如果根节点处父容器释放后,所有的子容器都将被释放。
class Program
{
    static void Main(string[] args)
    {
        UnityContainer parentContainer = new UnityContainer();

        UnityContainer childContainer = (UnityContainer )parentContainer.CreateChildContainer();

        // can use both generated objects here

        // Dispose child container
        childContainer.Dispose();

        // can use only object in parent container here

        // Dispose parent container
        parentContainer.Dispose();
    }
}

 

注册接口映射

在Unity中提供了RegisterType方法供我们在容器中注册接口映射:

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();

        container.RegisterType<ILogger, DatabaseLogger>();
        container.RegisterType<ILogger, FlatFileLogger>("flatfileLogger");
    }
}

 

第一个泛型参数是基类型,第二个泛型参数是组件类型,它们之间必须满足一定的泛型约束关系:

IUnityContainer RegisterType<TFrom, TTo>() where TTo : TFrom;

 

另外,如果在注册组件时没有指定我们也可以使用非泛型的RegisterType方法进行接口映射:

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();
        container.RegisterType(typeof(ILogger),typeof(DatabaseLogger));
        container.RegisterType(typeof(ILogger),typeof(FlatFileLogger),"flatfileLogger");
    }
}

 

 

获取对象实例

在Unity中提供了Get方法用以获取对象实例,如下代码所示:

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();

        container.RegisterType<ILogger, FlatFileLogger>();

        ILogger logger =  container.Resolve<ILogger>();

        logger.Write("TerryLee");
    }
}

 

  在上面代码中,我们在容器中注册了一个ILogger接口到FlatFileLogger的映射,当调用Resolve<ILogger>()方法时,将返回ILogger的一个默认的类型实例。

 

 

在之前注册接口映射部分,Register方法有一个重载是为接口映射指定一个特定的名称,这样我们可以根据名称和接口来获取一个特定类型的对象实例,如下面的代码我们同时注册FlatFileLogger和DatabaseLogger到接口ILogger的映射,并未DatabaseLogger指定一个名称,在使用Resolve方法的时候就可以通过ILogger和指定的名称来获取DatabaseLogger实例:

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();

        container.RegisterType<ILogger, FlatFileLogger>();
        container.RegisterType<ILogger, DatabaseLogger>("databaseLogger");

        ILogger logger = container.Resolve<ILogger>("databaseLogger");

        logger.Write("TerryLee");
    }
}

再运行代码,可以看到获取到了DatabaseLogger实例

 

 

如果我们同时同时注册FlatFileLogger和DatabaseLogger到接口ILogger的映射,并且不指定任何名称,那么直接调用Resolve方法将会返回后注册的组件的对象实例,如下面的代码:

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();

        container.RegisterType<ILogger, FlatFileLogger>();
        container.RegisterType<ILogger, DatabaseLogger>();

        ILogger logger = container.Resolve<ILogger>();

        logger.Write("TerryLee");
    }
}

 

运行后会返回DatabaseLogger实例:

 

 

当然我们也可以使用非泛型的Resolve方法来获取对象实例:

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();

        container.RegisterType<ILogger, FlatFileLogger>();

        ILogger logger = container.Get(typeof(ILogger)) as ILogger;

        logger.Write("TerryLee");
    }
}

 

获取所有对象实例

除了可以获取单个对象实例之外,我们还可以一次获取容器中所有与某一接口映射的所有对象实例,但是需要依赖于在注册映射时提供的名称,如果没有指定名称,通过ResolveAll方法不会被获取到。

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();

        container.RegisterType<ILogger, FlatFileLogger>();
        container.RegisterType<ILogger, FlatFileLogger>("flatFileLogger");
        container.RegisterType<ILogger, DatabaseLogger>("DatabaseLogger");
        IEnumerable<ILogger> loggers = container.ResolveAll<ILogger>();

        foreach (ILogger logger in loggers)
        {
            if (null != logger)
            {
                Console.WriteLine(logger.GetType().ToString());
            }
        }
    }
}

运行后如下,第一个没有提供名称的类型实例不会被获取到:

 

备注:

untity容器可以包含 Container-Configured Registration of Types  抽象接口式

  1. IUnityContainer myContainer = new UnityContainer();
  2. myContainer.RegisterType<IMyService, CustomerService>();
  3. IMyService myServiceInstance = myContainer.Resolve<IMyService>();

也可以在容器中包含 Container-Configured Registration of Existing Object Instances  存在实例

  1. IUnityContainer myContainer = new UnityContainer();
  2. LoggingService myExistingObject = new LoggingService();
  3. myContainer.RegisterInstance<IMyService>(myExistingObject);
  4. IMyService myServiceInstance = myContainer.Resolve<IMyService>();

灵活性比较突出,对于解耦和程序的松散型提供了非常好的支持。


 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值