161

我一直在阅读 MSDN 上有关 Unity(依赖注入、控制反转)的文章,但我认为我需要用简单的术语(或简单的示例)来解释它。我熟悉 MVPC 模式(我们在这里使用它),但我还不能真正掌握 Unity 的东西,我认为这是我们应用程序设计的下一步。

4

6 回答 6

180

Unity 只是一个 IoC“容器”。谷歌 StructureMap 并尝试一下。我认为,当 IoC 对你来说是新的东西时,更容易理解。

基本上,如果您了解 IoC,那么您就会明白您所做的是在创建对象时反转控件。

没有 IoC:

public class MyClass
{
   IMyService _myService; 

   public MyClass()
   {
      _myService = new SomeConcreteService();    
   }
}

使用 IoC 容器:

public class MyClass
{
   IMyService _myService; 

   public MyClass(IMyService myService)
   {
      _myService = myService;    
   }
}

如果没有 IoC,则依赖于 IMyService 的类必须更新要使用的服务的具体版本。这很糟糕,原因有很多(你已经将你的类耦合到 IMyService 的特定具体版本,你不能轻易地对其进行单元测试,你不能轻易地改变它等等)

使用 IoC 容器,您可以“配置”容器来为您解决这些依赖关系。因此,使用基于构造函数的注入方案,您只需将 IMyService 依赖项的接口传递给构造函数即可。当您使用容器创建 MyClass 时,您的容器将为您解析 IMyService 依赖项。

使用 StructureMap,配置容器如下所示:

StructureMapConfiguration.ForRequestedType<MyClass>().TheDefaultIsConcreteType<MyClass>();
StructureMapConfiguration.ForRequestedType<IMyService>().TheDefaultIsConcreteType<SomeConcreteService>();

所以你所做的就是告诉容器,“当有人请求 IMyService 时,给他们一份 SomeConcreteService 的副本。” 而且您还指定当有人请求 MyClass 时,他们会得到一个具体的 MyClass。

这就是 IoC 容器的全部功能。他们可以做得更多,但这就是它的主旨——他们为您解决依赖关系,因此您不必这样做(而且您不必在整个代码中使用“new”关键字)。

最后一步:当你创建你的 MyClass 时,你会这样做:

var myClass = ObjectFactory.GetInstance<MyClass>();

希望有帮助。随时给我发电子邮件。

于 2009-03-03T23:02:55.740 回答
39

我刚刚观看了 David Hayden 的 30 分钟 Unity Dependency Injection IoC Screencast,并觉得这是一个很好的示例解释。以下是节目说明的片段:

截屏视频展示了 Unity IoC 的几种常见用法,例如:

  • 创建不在容器中的类型
  • 注册和解析类型映射
  • 注册和解析命名类型映射
  • 单例、LifetimeManager 和 ContainerControlledLifetimeManager
  • 注册现有实例
  • 将依赖项注入现有实例
  • 通过 App.config / Web.config 填充 UnityContainer
  • 通过注入 API 指定依赖项,而不是依赖项属性
  • 使用嵌套(父子)容器
于 2009-05-26T00:52:29.200 回答
32

Unity 是一个与许多其他库一样的库,它允许您获取所请求类型的实例,而无需自己创建它。所以给的。

public interface ICalculator
{
    void Add(int a, int b);
}

public class Calculator : ICalculator
{
    public void Add(int a, int b)
    {
        return a + b;
    }
}

您将使用 Unity 之类的库来注册 Calculator,以便在请求 ICalculator 类型时返回,即 IoC(控制反转)(此示例是理论上的,在技术上不正确)。

IoCLlibrary.Register<ICalculator>.Return<Calculator>();

所以现在当你想要一个 ICalculator 的实例时,你只需......

Calculator calc = IoCLibrary.Resolve<ICalculator>();

IoC 库通常可以配置为在每次解析类型时保存单例或创建新实例。

现在假设你有一个依赖于 ICalculator 的类,你可以拥有..

public class BankingSystem
{
    public BankingSystem(ICalculator calc)
    {
        _calc = calc;
    }

    private ICalculator _calc;
}

您可以设置库以在创建对象时将对象注入构造函数。

因此 DI 或依赖注入意味着注入另一个可能需要的任何对象。

于 2009-03-03T23:05:14.707 回答
10

Unity 是一个 IoC。IoC 的重点是在类型本身之外抽象类型之间的依赖关系。这有几个优点。首先,它是集中完成的,这意味着当依赖关系发生变化时您不必更改大量代码(单元测试可能就是这种情况)。

此外,如果使用配置数据而不是代码完成连接,您实际上可以在部署后重新连接依赖关系,从而在不更改代码的情况下更改应用程序的行为。

于 2009-03-04T00:33:51.530 回答
5

MSDN 有一个Developer's Guide to Dependency Injection Using Unity,它可能很有用。

开发人员指南首先介绍了依赖注入的基础知识,然后是如何使用 Unity 进行依赖注入的示例。截至 2014 年 2 月,开发人员指南涵盖了 2013 年 4 月发布的 Unity 3.0。

于 2014-02-11T20:24:29.610 回答
1

我将介绍 ASP.NET Web API 2 中的大多数依赖注入示例

public interface IShape
{
    string Name { get; set; }
}

public class NoShape : IShape
{
    public string Name { get; set; } = "I have No Shape";
}

public class Circle : IShape
{
    public string Name { get; set; } = "Circle";
}

public class Rectangle : IShape
{
    public Rectangle(string name)
    {
        this.Name = name;
    }

    public string Name { get; set; } = "Rectangle";
}

在 DIAutoV2Controller.cs 中使用了自动注入机制

[RoutePrefix("api/v2/DIAutoExample")]
public class DIAutoV2Controller : ApiController
{
    private string ConstructorInjected;
    private string MethodInjected1;
    private string MethodInjected2;
    private string MethodInjected3;

    [Dependency]
    public IShape NoShape { get; set; }

    [Dependency("Circle")]
    public IShape ShapeCircle { get; set; }

    [Dependency("Rectangle")]
    public IShape ShapeRectangle { get; set; }

    [Dependency("PiValueExample1")]
    public double PiValue { get; set; }

    [InjectionConstructor]
    public DIAutoV2Controller([Dependency("Circle")]IShape shape1, [Dependency("Rectangle")]IShape shape2, IShape shape3)
    {
        this.ConstructorInjected = shape1.Name + " & " + shape2.Name + " & " + shape3.Name;
    }

    [NonAction]
    [InjectionMethod]
    public void Initialize()
    {
        this.MethodInjected1 = "Default Initialize done";
    }

    [NonAction]
    [InjectionMethod]
    public void Initialize2([Dependency("Circle")]IShape shape1)
    {
        this.MethodInjected2 = shape1.Name;
    }

    [NonAction]
    [InjectionMethod]
    public void Initialize3(IShape shape1)
    {
        this.MethodInjected3 = shape1.Name;
    }

    [HttpGet]
    [Route("constructorinjection")]
    public string constructorinjection()
    {
        return "Constructor Injected: " + this.ConstructorInjected;
    }

    [HttpGet]
    [Route("GetNoShape")]
    public string GetNoShape()
    {
        return "Property Injected: " + this.NoShape.Name;
    }

    [HttpGet]
    [Route("GetShapeCircle")]
    public string GetShapeCircle()
    {
        return "Property Injected: " + this.ShapeCircle.Name;
    }

    [HttpGet]
    [Route("GetShapeRectangle")]
    public string GetShapeRectangle()
    {
        return "Property Injected: " + this.ShapeRectangle.Name;
    }

    [HttpGet]
    [Route("GetPiValue")]
    public string GetPiValue()
    {
        return "Property Injected: " + this.PiValue;
    }

    [HttpGet]
    [Route("MethodInjected1")]
    public string InjectionMethod1()
    {
        return "Method Injected: " + this.MethodInjected1;
    }

    [HttpGet]
    [Route("MethodInjected2")]
    public string InjectionMethod2()
    {
        return "Method Injected: " + this.MethodInjected2;
    }

    [HttpGet]
    [Route("MethodInjected3")]
    public string InjectionMethod3()
    {
        return "Method Injected: " + this.MethodInjected3;
    }
}

在 DIV2Controller.cs 中,所有内容都将从 Dependency Configuration Resolver 类中注入

[RoutePrefix("api/v2/DIExample")]
public class DIV2Controller : ApiController
{
    private string ConstructorInjected;
    private string MethodInjected1;
    private string MethodInjected2;
    public string MyPropertyName { get; set; }
    public double PiValue1 { get; set; }
    public double PiValue2 { get; set; }
    public IShape Shape { get; set; }

    // MethodInjected
    [NonAction]
    public void Initialize()
    {
        this.MethodInjected1 = "Default Initialize done";
    }

    // MethodInjected
    [NonAction]
    public void Initialize2(string myproperty1, IShape shape1, string myproperty2, IShape shape2)
    {
        this.MethodInjected2 = myproperty1 + " & " + shape1.Name + " & " + myproperty2 + " & " + shape2.Name;
    }

    public DIV2Controller(string myproperty1, IShape shape1, string myproperty2, IShape shape2)
    {
        this.ConstructorInjected = myproperty1 + " & " + shape1.Name + " & " + myproperty2 + " & " + shape2.Name;
    }

    [HttpGet]
    [Route("constructorinjection")]
    public string constructorinjection()
    {
        return "Constructor Injected: " + this.ConstructorInjected;
    }

    [HttpGet]
    [Route("PropertyInjected")]
    public string InjectionProperty()
    {
        return "Property Injected: " + this.MyPropertyName;
    }

    [HttpGet]
    [Route("GetPiValue1")]
    public string GetPiValue1()
    {
        return "Property Injected: " + this.PiValue1;
    }

    [HttpGet]
    [Route("GetPiValue2")]
    public string GetPiValue2()
    {
        return "Property Injected: " + this.PiValue2;
    }

    [HttpGet]
    [Route("GetShape")]
    public string GetShape()
    {
        return "Property Injected: " + this.Shape.Name;
    }

    [HttpGet]
    [Route("MethodInjected1")]
    public string InjectionMethod1()
    {
        return "Method Injected: " + this.MethodInjected1;
    }

    [HttpGet]
    [Route("MethodInjected2")]
    public string InjectionMethod2()
    {
        return "Method Injected: " + this.MethodInjected2;
    }
}

配置依赖解析器

public static void Register(HttpConfiguration config)
{
    var container = new UnityContainer();
    RegisterInterfaces(container);
    config.DependencyResolver = new UnityResolver(container);

    // Other Web API configuration not shown.
}

private static void RegisterInterfaces(UnityContainer container)
{
    var dbContext = new SchoolDbContext();
    // Registration with constructor injection
    container.RegisterType<IStudentRepository, StudentRepository>(new InjectionConstructor(dbContext));
    container.RegisterType<ICourseRepository, CourseRepository>(new InjectionConstructor(dbContext));

    // Set constant/default value of Pi = 3.141 
    container.RegisterInstance<double>("PiValueExample1", 3.141);
    container.RegisterInstance<double>("PiValueExample2", 3.14);

    // without a name
    container.RegisterInstance<IShape>(new NoShape());

    // with circle name
    container.RegisterType<IShape, Circle>("Circle", new InjectionProperty("Name", "I am Circle"));

    // with rectangle name
    container.RegisterType<IShape, Rectangle>("Rectangle", new InjectionConstructor("I am Rectangle"));

    // Complex type like Constructor, Property and method injection
    container.RegisterType<DIV2Controller, DIV2Controller>(
        new InjectionConstructor("Constructor Value1", container.Resolve<IShape>("Circle"), "Constructor Value2", container.Resolve<IShape>()),
        new InjectionMethod("Initialize"),
        new InjectionMethod("Initialize2", "Value1", container.Resolve<IShape>("Circle"), "Value2", container.Resolve<IShape>()),
        new InjectionProperty("MyPropertyName", "Property Value"),
        new InjectionProperty("PiValue1", container.Resolve<double>("PiValueExample1")),
        new InjectionProperty("Shape", container.Resolve<IShape>("Rectangle")),
        new InjectionProperty("PiValue2", container.Resolve<double>("PiValueExample2")));
}
于 2018-06-30T20:27:57.197 回答