Может кто-нибудь объяснить Microsoft Unity?


Я читал статьи на MSDN о Unity (инъекция зависимостей, инверсия управления), но я думаю, что мне нужно это объяснить простыми словами (или простыми примерами). Я знаком с шаблоном MVPC (мы используем его здесь), но я просто не могу понять эту вещь единства, и я думаю, что это следующий шаг в нашем дизайне приложения.

7 132

7 ответов:

Unity-это просто "контейнер" МОК. Google StructureMap и попробовать его вместо этого. Немного легче Грок, я думаю, когда материал МОК является новым для вас.

в принципе, если вы понимаете IoC, то вы понимаете, что то, что вы делаете, это инвертирование элемента управления при создании объекта.

Без МОК:

public class MyClass
{
   IMyService _myService; 

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

с контейнером МОК:

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>();

надеюсь, что это поможет. Не стесняйтесь, пишите мне.

Я просто смотрел 30-минутную инъекцию зависимости от Unity IOC Screencast Дэвида Хейдена и чувствовал, что это хорошее объяснение с примерами. Вот фрагмент из заметок шоу:

скринкаст показывает несколько общих обычаев МОК Unity, таких как:

  • Создание Типов Не В Контейнере
  • регистрация и разрешение TypeMappings
  • регистрация и разрешение именованных TypeMappings
  • синглтоны, LifetimeManagers и ContainerControlledLifetimeManager
  • Регистрация Существующих Экземпляров
  • инъекция зависимостей в существующие экземпляры
  • заполнение UnityContainer через приложение.config / Web.конфигурации
  • указание зависимостей через API инъекций в отличие от атрибутов зависимостей
  • Использование Вложенных (Родительских-Дочерних ) Контейнеров

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, чтобы зарегистрировать калькулятор, который будет возвращен, когда тип ICalculator запрашивается aka IoC (инверсия Управления) (этот пример теоретический, а не технически правильный).

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

так что теперь, когда вы хотите экземпляр ICalculator вы просто...

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

МОК библиотеки обычно можно настроить для хранения одного элемента или создания нового экземпляра при каждом разрешении типа.

теперь предположим, что у вас есть класс, который полагается на ICalculator, чтобы присутствовать вы могли бы иметь..

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

    private ICalculator _calc;
}

и вы можете настроить библиотеку, чтобы ввести объект в конструктор при ее создании.

таким образом, DI или инъекция зависимостей означает введение любого объекта, который может потребоваться другому.

этот парень WilcoxTutorials дает отличную демонстрацию контейнера Unity, который нацелен на новичков.

Часть 1 http://www.youtube.com/watch?v=CWwe9Z0Gyew

Часть 2:http://www.youtube.com/watch?v=PsIbevgzQQE

менее чем через полчаса, и вы поймете основы!

Unity - это МОК. Смысл МОК заключается в том, чтобы абстрагировать проводку зависимостей между типами вне самих типов. Это имеет несколько преимуществ. Прежде всего, это делается централизованно, что означает, что вам не нужно менять много кода при изменении зависимостей (что может иметь место для модульных тестов).

кроме того, если проводка выполняется с использованием данных конфигурации вместо кода, Вы можете фактически перемонтировать зависимости после развертывания и, таким образом, изменить поведение приложения без изменения кода.

MSDN имеет руководство разработчика ПО инъекции зависимостей с использованием Unity это может быть полезно.

руководство разработчика начинается с основ того, что такое инъекция зависимостей, и продолжается примерами использования Unity для инъекции зависимостей. По состоянию на февраль 2014 года руководство разработчика охватывает Unity 3.0, который был выпущен в апреле 2013 года.

я освещаю большинство примеров внедрения зависимостей в 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 все будет введено из класса решателя конфигурации зависимостей

[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")));
}