Birisi Microsoft Unity'yi açıklayabilir mi?


157

MSDN'de Unity (Bağımlılık Enjeksiyonu, Kontrolün Ters Çevrilmesi) hakkındaki makaleleri okudum, ancak basit terimlerle (veya basit örneklerle) açıklanmasına ihtiyacım olduğunu düşünüyorum. MVPC modeline aşinayım (burada kullanıyoruz), ancak henüz bu Birlik şeyi gerçekten kavrayamıyorum ve uygulama tasarımımızda bir sonraki adım olduğunu düşünüyorum.


12
Bunun "Unity" ile aynı ada sahip olmasını seviyorum, bu yüzden Unity Game Engine şeyler ararken bu eski teknolojiyi görüyorum, iç çek. Tüm iyi grup isimleri alındı ​​sanırım.
Tom Schulz

2
@ tom-schulz Eski teknoloji? nuget.org/packages/Unity - en son 5 gün önce güncellendi.
Roger Willcocks

Yanıtlar:


174

Birlik sadece bir IoC "konteyneri" dir. Google StructureMap ve bunun yerine deneyin. IoC işleri sizin için yeni olduğunda, bence biraz daha kolay.

Temel olarak, IoC'yi anlarsanız, yaptığınız şeyin bir nesne oluşturulduğunda kontrolü tersine çevirdiğini anlarsınız.

IoC olmadan:

public class MyClass
{
   IMyService _myService; 

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

IoC konteyneri ile:

public class MyClass
{
   IMyService _myService; 

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

IoC olmadan, IMyService'e dayanan sınıfınız, kullanılacak hizmetin somut bir versiyonunu yenilemelidir. Ve bu birkaç nedenden dolayı kötüdür (sınıfınızı IMyService'in belirli bir somut sürümüne bağladınız, kolayca test edemezsiniz, kolayca değiştiremezsiniz, vb.)

Bir IoC kapsayıcısıyla, kapsayıcıyı sizin için bu bağımlılıkları çözmek üzere "yapılandırabilirsiniz". Böylece yapıcı tabanlı bir enjeksiyon şemasıyla, arayüzü IMyService bağımlılığına yapıcıya geçirirsiniz. MyClass'ı konteynerinizle oluşturduğunuzda, konteyneriniz IMyService bağımlılığını sizin için çözecektir.

StructureMap'i kullanarak kapsayıcıyı yapılandırmak şöyle görünür:

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

Böylece, yaptığınız kapsayıcıya "Birisi IMyService'i istediğinde, onlara SomeConcreteService'in bir kopyasını verin." Ayrıca birisi MyClass istediğinde somut bir MyClass aldığını belirttiniz.

Tüm bunlar bir IoC konteynerinin gerçekten yaptığı. Daha fazlasını yapabilirler, ancak bu itiş gücüdür - sizin için bağımlılıkları çözerler, böylece yapmanız gerekmez (ve kodunuz boyunca "yeni" anahtar kelimeyi kullanmanız gerekmez).

Son adım: MyClass'ınızı oluşturduğunuzda bunu yaparsınız:

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

Umarım yardımcı olur. Bana e-posta göndermekten çekinmeyin.


2
Sanırım bir fabrika gibi, sanırım? Bunu doğru bir şekilde izlersem, son örnekte <MyClass> yerine <IMyClass> kullanmaz mıydınız? bu yüzden var olur myClass = ObjectFactory.GetInstance <IMyClass> ()? Yardımınız için teşekkürler, bu benim için iyi bir başlangıç!
Ryan Abbott

3
Bir bakıma, bir fabrika gibi, evet. Uygulamanız için bir ana fabrika. Ancak teklitonlar da dahil olmak üzere birçok farklı tür döndürecek şekilde yapılandırılabilir. MyClass arayüzüne gelince - eğer bir iş nesnesi varsa, bir arayüz çıkarmam. Diğer her şey için genellikle isterim.
Chris Holmes

yalnızca ObjectFactory.GetInstance <MyClass> () öğesini çağırdıysanız; ve SomeConcreteClass'ı yapılandırmadınız mı? Bu durumda hata alıp verir misiniz?
RayLoveless

1
@Ray: Konteynere bağlıdır. Bazı kapsayıcılar, varsayılan olarak bir sınıflandırma MyClass ve arabirim IMyInterface olarak adlandırılmışsa, kapsayıcı o sınıfı o arabirim için otomatik olarak yapılandıracak şekilde bir adlandırma kuralı kullanacak şekilde yazılır. Bu durumda, elle yapılandırmazsanız, kabın varsayılan "kuralı" yine de onu alır. Ancak, sınıfınız ve arabiriminiz kurallara uymazsa ve kapsayıcıyı bu sınıf için yapılandırmazsanız, evet, çalışma zamanında bir hata alırsınız.
Chris Holmes

1
@saravanan Sanırım StructureMap şimdi isme dayalı bir toplantı yapıyor. Ben emin değilim; uzun zamandır kullanmadık (işimiz için özel bir tane yazdım; arayüzler ve sınıflar için aynı isim kuralını kullanıyor).
Chris Holmes

39

David Hayden'ın 30 dakikalık Birlik Bağımlılığı Enjeksiyonu IoC Screencast'ı izledim ve bunun örneklerle iyi bir açıklama olduğunu hissettim. İşte şov notlarından bir pasaj:

Ekran görüntüsü, Unity IoC'nin birkaç yaygın kullanımını gösterir, örneğin:

  • Kapsayıcıda Olmayan Türler Oluşturma
  • Kayıt ve Çözümleme Türü
  • İsimli Tip Kayıtlarını Kaydetme ve Çözme
  • Singletons, LifetimeManagers ve ContainerControlledLifetimeManager
  • Mevcut Örnekleri Kaydetme
  • Mevcut Örneklere Bağımlılık Ekleme
  • UnityContainer'ı App.config / Web.config aracılığıyla doldurma
  • Bağımlılık Özelliklerinin aksine Enjeksiyon API'sı ile Bağımlılıkları Belirtme
  • Yuvalanmış (Ebeveyn-Çocuk) Konteynerleri Kullanma

32

Unity, başkaları gibi, kendiniz oluşturmak zorunda kalmadan istenen türde bir örnek almanızı sağlayan bir kütüphanedir. Böylece verildi.

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

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

ICalculator türü olarak IoC (Kontrolün Ters Çevrilmesi) istendiğinde döndürülecek Hesap Makinesi'ni kaydetmek için Unity gibi bir kütüphane kullanırsınız (bu örnek teoriktir, teknik olarak doğru değildir).

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

Şimdi bir ICalculator örneği istediğinizde ...

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

IoC kitaplıkları genellikle bir türü her çözdüğünüzde tek birton tutacak veya yeni bir örnek oluşturacak şekilde yapılandırılabilir.

Şimdi, sahip olabileceğiniz bir ICalculator'a dayanan bir sınıfınız olduğunu varsayalım.

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

    private ICalculator _calc;
}

Ayrıca, kitaplığı oluşturulduğunda yapıcıya bir nesne enjekte edecek şekilde ayarlayabilirsiniz.

Dolayısıyla DI veya Bağımlılık Enjeksiyonu, başka bir kişinin gerektirebileceği herhangi bir nesneyi enjekte etmek anlamına gelir.


ICalculator calc = IoCLibrary olmalıdır. <ICalculator> ();
Shukhrat Raimov


10

Birlik bir IoC'dir. IoC'nin amacı, türlerin dışındaki türler arasındaki bağımlılıkların kablolarını soyutlamaktır. Bunun birkaç avantajı var. Her şeyden önce, merkezi olarak yapılır, bu da bağımlılıklar değiştiğinde çok fazla kod değiştirmeniz gerekmediği anlamına gelir (birim testleri için durum böyle olabilir).

Ayrıca, kablolama kod yerine konfigürasyon verileri kullanılarak yapılırsa, dağıtımdan sonra bağımlılıkları yeniden oluşturabilir ve böylece kodu değiştirmeden uygulamanın davranışını değiştirebilirsiniz.



1

ASP.NET Web API 2'de Bağımlılık Enjeksiyonu örneklerinin çoğunu kapsıyorum

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 içinde Otomatik Enjeksiyon mekanizması kullanılır

[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 dosyasında her şey Bağımlılık Yapılandırma Çözücü sınıfından enjekte edilecektir

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

Bağımlılık Çözücüyü Yapılandırma

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

Bu, çeşitli nedenlerden dolayı özellikle yararlı bir cevap değildir. Bu, IOC'nin basit bir açıklamasını sunmada yararlı olmak için çok fazla kod içeren gereksiz karmaşık bir örnektir. Bunun yanı sıra, kod gerçekten ihtiyacınız olan yerlerde açıkça belgelenmemiştir.
Dan Atkinson
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.