详解C#中的依赖注入和IoC容器

论坛 期权论坛 脚本     
niminba   2021-5-23 03:29   1823   0

在本文中,我们将通过用C#重构一个非常简单的代码示例来解释依赖注入和IoC容器。 

简介:

依赖注入和IoC乍一看可能相当复杂,但它们非常容易学习和理解。

在本文中,我们将通过在C#中重构一个非常简单的代码示例来解释依赖注入和IoC容器。

要求:

构建一个允许用户查看可用产品并按名称搜索产品的应用程序。

第一次尝试:

我们将从创建分层架构开始。使用分层架构有多个好处,但我们不会在本文中列出它们,因为我们关注的是依赖注入。

下面是应用程序的类图:

首先,我们将从创建一个Product类开始:

public class Product
{
  public Guid Id { get; set; }
  public string Name { get; set; }
  public string Description { get; set; }
}

然后,我们将创建数据访问层:

public class ProductDAL
{
  private readonly List<Product> _products;

  public ProductDAL()
  {
    _products = new List<Product>
    {
      new Product { Id = Guid.NewGuid(), Name= "iPhone 9", 
             Description = "iPhone 9 mobile phone" },
      new Product { Id = Guid.NewGuid(), Name= "iPhone X", 
             Description = "iPhone X mobile phone" }
    };
  }

  public IEnumerable<Product> GetProducts()
  {
    return _products;
  }

  public IEnumerable<Product> GetProducts(string name)
  {
    return _products
      .Where(p => p.Name.Contains(name))
      .ToList();
  }
}

然后,我们将创建业务层:

public class ProductBL
{
  private readonly ProductDAL _productDAL;

  public ProductBL()
  {
    _productDAL = new ProductDAL();
  }

  public IEnumerable<Product> GetProducts()
  {
    return _productDAL.GetProducts();
  }

  public IEnumerable<Product> GetProducts(string name)
  {
    return _productDAL.GetProducts(name);
  }
}

最后,我们将创建UI:

class Program
{
  static void Main(string[] args)
  {
    ProductBL productBL = new ProductBL();

    var products = productBL.GetProducts();

    foreach (var product in products)
    {
      Console.WriteLine(product.Name);
    }

    Console.ReadKey();
  }
}

我们已经写在第一次尝试的代码是良好的工作成果,但有几个问题:

1.我们不能让三个不同的团队在每个层上工作。

2.业务层很难扩展,因为它依赖于数据访问层的实现。

3.业务层很难维护,因为它依赖于数据访问层的实现。

4.源代码很难测试。

第二次尝试:

高级别对象不应该依赖于低级别对象。两者都必须依赖于抽象。那么抽象概念是什么呢?

抽象是功能的定义。在我们的例子中,业务层依赖于数据访问层来检索图书。在C#中,我们使用接口实现抽象。接口表示功能的抽象。

让我们来创建抽象。

下面是数据访问层的抽象:

public interface IProductDAL
{
  IEnumerable<Product> GetProducts();
  IEnumerable<Product> GetProducts(string name);
}

我们还需要更新数据访问层:

public class ProductDAL : IProductDAL

我们还需要更新业务层。实际上,我们将更新业务层,使其依赖于数据访问层的抽象,而不是依赖于数据访问层的实现:

public class ProductBL
{
  private readonly IProductDAL _productDAL;

  public ProductBL()
  {
    _productDAL = new ProductDAL();
  }

  public IEnumerable<Product> GetProducts()
  {
    return _productDAL.GetProducts();
  }

  public IEnumerable<Product> GetProducts(string name)
  {
    return _productDAL.GetProducts(name);
  }
}

我们还必须创建业务层的抽象:

public interface IProductBL
{
  IEnumerable<Product> GetProducts();
  IEnumerable<Product> GetProducts(string name);
}

我们也需要更新业务层:

public class ProductBL : IProductBL

最终我们需要更新UI:

class Program
{
  static void Main(string[] args)
  {
    IProductBL productBL = new ProductBL();

    var products = productBL.GetProducts();

    foreach (var product in products)
    {
      Console.WriteLine(product.Name);
    }

    Console.ReadKey();
  }
}

我们在第二次尝试中所rface)Activator.CreateInstance(typeOfImpl); } }

最终,我们会更新UI:

class Program
{
  static void Main(string[] args)
  {
    var container = new Container();
    container.RegisterTransient<IProductDAL, ProductDAL>();

    IProductBL productBL = new ProductBL(container.Create<IProductDAL>());
    var products = productBL.GetProducts();

    foreach (var product in products)
    {
      Console.WriteLine(product.Name);
    }

    Console.ReadKey();
  }
}

现在,让我们在容器中实现Resolve方法。此方法将解决依赖关系。

Resolve方法如下:

public T Resolve<T>()
{
    var ctor = ((Type)_registrations[typeof(T)]).GetConstructors()[0];
    var dep = ctor.GetParameters()[0].ParameterType;
    var mi = typeof(Container).GetMethod("Create");
    var gm = mi.MakeGenericMethod(dep);
    return (T)ctor.Invoke(new object[] { gm.Invoke(this, null) });
}

然后我们可以在UI中使用如下Resolve方法:

class Program
{
    static void Main(string[] args)
    {
        var container = new Container();
        container.RegisterTransient<IProductDAL, ProductDAL>();
        container.RegisterTransient<IProductBL, ProductBL>();

        var productBL = container.Resolve<IProductBL>();
        var products = productBL.GetProducts();

        foreach (var product in products)
        {
            Console.WriteLine(product.Name);
        }

        Console.ReadKey();
    }
}

在上面的源代码中,容器使用container.Resolve<IProductBL>()方法创建ProductBL类的一个对象。ProductBL类是IProductDAL的一个依赖项。因此,container.Resolve<IProductBL>() 通过自动创建并在其中注入一个ProductDAL对象返回ProductBL类的一个对象。这一切都在幕后进行。创建和注入ProductDAL对象是因为我们用IProductDAL注册了ProductDAL类型。

这是一个非常简单和基本的IoC容器,它向你展示了IoC容器背后的内容。就是这样。我希望你喜欢阅读这篇文章。

以上就是详解C#中的依赖注入和IoC容器的详细内容,更多关于C# 依赖注入和IoC容器的资料请关注社区其它相关文章!

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1060120
帖子:212021
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP