누군가 Microsoft Unity를 설명 할 수 있습니까?


157

MSDN에 대한 Unity (Dependency Injection, Inversion of Control)에 대한 기사를 읽었지만 간단한 용어 (또는 간단한 예)로 설명해야한다고 생각합니다. MVPC 패턴에 익숙하지만 (여기서는 여기에서 사용)이 Unity를 아직 파악할 수 없으며 애플리케이션 디자인의 다음 단계라고 생각합니다.


12
나는 이것이 "Unity"와 같은 이름을 갖는 것을 좋아합니다. 그래서 Unity Game Engine을 검색 할 때이 오래된 기술이 보입니다. 모든 좋은 밴드 이름이 사용됩니다.
Tom Schulz

2
@ tom-schulz Old tech? nuget.org/packages/Unity-5 일 전에 마지막 업데이트.
Roger Willcocks

답변:


174

Unity는 IoC "컨테이너"입니다. Google 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 컨테이너가 실제로하는 전부입니다. 그들은 더 많은 일을 할 수 있지만, 그것은 추력입니다-그들은 당신을 위해 의존성을 해결하므로, 필요하지 않습니다 (그리고 코드 전체에서 "새"키워드를 사용할 필요가 없습니다).

마지막 단계 : MyClass를 만들 때 다음을 수행하십시오.

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

희망이 도움이됩니다. 저에게 이메일을 보내 주시기 바랍니다.


2
공장 같아요? 올바르게 수행하면 마지막 예에서 <MyClass> 대신 <IMyClass>를 사용하지 않습니까? 그래서 var myClass = ObjectFactory.GetInstance <IMyClass> ()입니까? 당신의 도움에 감사드립니다, 이것은 나에게 좋은 시작입니다!
Ryan Abbott

3
어떤면에서 그것은 공장과 같습니다. 예. 어플리케이션을위한 마스터 팩토리. 그러나 싱글 톤을 포함하여 다양한 유형을 반환하도록 구성 할 수 있습니다. MyClass에 대한 인터페이스는 비즈니스 객체 인 경우 인터페이스를 추출하지 않습니다. 다른 모든 것에는 일반적으로 할 것입니다.
Chris Holmes

ObjectFactory.GetInstance <MyClass> (); 만 호출하면 어떻게됩니까? SomeConcreteClass를 구성하지 않았습니까? 이 경우 오류가 발생합니까?
RayLoveless 2016 년

1
@ 레이 : 컨테이너에 따라 다릅니다. 일부 컨테이너는 기본적으로 명명 규칙을 사용하여 클래스 이름이 MyClass이고 인터페이스 이름이 IMyInterface 인 경우 컨테이너가 해당 인터페이스에 대해 해당 클래스를 자동으로 구성하도록 명명 규칙을 사용합니다. 이 경우 수동으로 구성하지 않으면 컨테이너의 기본 "컨벤션"이 컨테이너를 선택합니다. 그러나 클래스와 인터페이스가 규칙을 따르지 않고 해당 클래스에 대한 컨테이너를 구성하지 않으면 런타임에 오류가 발생합니다.
Chris Holmes

1
@saravanan StructureMap이 이제 이름 기반 규칙을 수행한다고 생각합니다. 나는 확실하지 않다. 우리는 오랫동안 그것을 사용하지 않았습니다 (저는 비즈니스를 위해 맞춤형을 작성했습니다. 인터페이스와 클래스에 대해 동일한 이름 규칙을 사용합니다).
Chris Holmes

39

방금 David Hayden의 30 분 Unity Dependency Injection IoC Screencast를 보았고 그 예가 좋은 설명이라고 생각했습니다. 다음은 쇼 노트의 스 니펫입니다.

스크린 캐스트는 Unity IoC의 몇 가지 일반적인 사용법을 보여줍니다.

  • 컨테이너에없는 유형 만들기
  • 타입 맵핑 등록 및 해결
  • 명명 된 형식 매핑 등록 및 해결
  • 싱글 톤, LifetimeManager 및 ContainerControlledLifetimeManager
  • 기존 인스턴스 등록
  • 기존 인스턴스에 종속성 주입
  • App.config / Web.config를 통해 UnityContainer 채우기
  • 종속성 속성이 아닌 주입 API를 통해 종속성 지정
  • 중첩 (부모-자식) 컨테이너 사용

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와 같은 라이브러리를 사용하여 ICalculator 유형 (일명 IoC (Inversion of Control))이 요청 될 때 계산기가 반환되도록 계산기를 등록 할 수 있습니다 (이 예제는 이론적으로는 정확하지 않습니다).

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 또는 Dependency Injection은 다른 개체에 필요할 수있는 개체를 주입하는 것을 의미합니다.


ICalculator 여야합니다. calc = IoCLibrary.Resolve <ICalculator> ();
Shukhrat Raimov


10

Unity는 IoC입니다. IoC의 요점은 유형 자체 외부의 유형 간 종속성 배선을 추상화하는 것입니다. 이것은 몇 가지 장점이 있습니다. 우선, 그것은 중앙에서 수행되므로 종속성이 변경 될 때 많은 단위를 변경할 필요가 없습니다 (단위 테스트의 경우 일 수 있음).

또한 코드 대신 구성 데이터를 사용하여 배선을 수행하는 경우 실제로 배포 후 종속성을 다시 배선하여 코드를 변경하지 않고도 응용 프로그램의 동작을 변경할 수 있습니다.


5

MSDN에는 Unity사용한 종속성 주입에 대한 개발자 안내서 가 있으며 유용 할 수 있습니다.

Developer 's Guide는 의존성 주입의 기본 사항으로 시작하며 의존성 주입에 Unity를 사용하는 방법에 대한 예제를 계속합니다. 2014 년 2 월 현재 개발자 안내서는 2013 년 4 월에 릴리스 된 Unity 3.0에 대해 설명합니다.


1

ASP.NET Web API 2의 Dependency Injection 예제를 대부분 다루고 있습니다.

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

여러 가지 이유로 특히 유용한 답변이 아닙니다. IOC에 대한 간단한 설명을 제공하는 데 유용한 코드가 너무 많은 불필요하게 복잡한 예입니다. 그 외에도 실제로 필요한 곳에 코드가 명확하게 문서화되어 있지 않습니다.
Dan Atkinson
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.