wake-up-neo.com

Kann jemand Microsoft Unity erklären?

Ich habe die Artikel auf MSDN über Unity (Abhängigkeitsinjektion, Inversion der Steuerung) gelesen, aber ich glaube, ich muss sie in einfachen Begriffen (oder einfachen Beispielen) erklären. Ich bin mit dem MVPC-Muster vertraut (wir verwenden es hier), aber ich kann diese Unity-Sache noch nicht wirklich verstehen, und ich denke, es ist der nächste Schritt in unserem Anwendungsdesign.

151
Ryan Abbott

Einheit ist nur ein IoC "Container". Google StructureMap und probieren Sie es stattdessen aus. Ein bisschen leichter zu fassen, denke ich, wenn dir das IoC-Zeug neu ist.

Wenn Sie IoC verstehen, verstehen Sie im Grunde, dass Sie das Steuerelement invertieren, wenn ein Objekt erstellt wird.

Ohne IoC:

public class MyClass
{
   IMyService _myService; 

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

Mit IoC-Container:

public class MyClass
{
   IMyService _myService; 

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

Ohne IoC muss Ihre Klasse, die sich auf den IMyService stützt, eine konkrete Version des zu verwendenden Dienstes aktualisieren. Und das ist aus einer Reihe von Gründen schlecht (Sie haben Ihre Klasse an eine bestimmte konkrete Version des IMyService gekoppelt, Sie können es nicht einfach testen, Sie können es nicht einfach ändern usw.)

Mit einem IoC-Container "konfigurieren" Sie den Container, um diese Abhängigkeiten für Sie aufzulösen. Bei einem konstruktorbasierten Injektionsschema übergeben Sie die Schnittstelle zur IMyService-Abhängigkeit einfach an den Konstruktor. Wenn Sie die MyClass mit Ihrem Container erstellen, löst Ihr Container die IMyService-Abhängigkeit für Sie auf.

Mit StructureMap sieht die Konfiguration des Containers folgendermaßen aus:

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

Sie haben also dem Container mitgeteilt: "Wenn jemand den IMyService anfordert, geben Sie ihm eine Kopie des SomeConcreteService." Und Sie haben auch festgelegt, dass jemand, der nach einer MyClass fragt, eine konkrete MyClass erhält.

Das ist alles, was ein IoC-Container wirklich tut. Sie können mehr, aber das ist der springende Punkt - sie lösen Abhängigkeiten für Sie auf, sodass Sie dies nicht tun müssen (und Sie müssen das Schlüsselwort "new" nicht im gesamten Code verwenden).

Letzter Schritt: Wenn Sie Ihre MyClass erstellen, würden Sie dies tun:

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

Hoffentlich hilft das. Fühlen Sie sich frei, mir eine E-Mail zu senden.

169
Chris Holmes

Ich habe mir gerade den 30-minütigen IoC-Screencast von Unity Dependency Injection von David Hayden angesehen und fand, dass dies eine gute Erklärung mit Beispielen ist. Hier ist ein Ausschnitt aus den Shownotizen:

Der Screencast zeigt verschiedene gebräuchliche Verwendungen von Unity IoC, wie zum Beispiel:

  • Typen erstellen, die sich nicht im Container befinden
  • Registrieren und Auflösen von TypeMappings
  • Registrieren und Auflösen von benannten TypeMappings
  • Singletons, LifetimeManager und der ContainerControlledLifetimeManager
  • Registrieren vorhandener Instanzen
  • Injizieren von Abhängigkeiten in vorhandene Instanzen
  • Füllen Sie den UnityContainer über App.config/Web.config
  • Festlegen von Abhängigkeiten über die Injection-API im Gegensatz zu Abhängigkeitsattributen
  • Verwenden von verschachtelten (Eltern-Kind-) Containern
36
Kevin Hakanson

Unity ist eine Bibliothek wie viele andere, mit der Sie eine Instanz eines angeforderten Typs abrufen können, ohne sie selbst erstellen zu müssen. So gegeben.

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

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

Sie würden eine Bibliothek wie Unity verwenden, um Calculator zu registrieren, der zurückgegeben wird, wenn der Typ ICalculator als IoC (Inversion of Control) angefordert wird (dieses Beispiel ist theoretisch, technisch nicht korrekt).

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

Wenn Sie also eine Instanz eines ICalculators möchten, müssen Sie nur ...

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

IoC-Bibliotheken können normalerweise so konfiguriert werden, dass sie bei jedem Auflösen eines Typs entweder ein Singleton enthalten oder eine neue Instanz erstellen.

Nehmen wir an, Sie haben eine Klasse, die sich darauf stützt, dass ein ICalculator anwesend ist, den Sie haben könnten.

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

    private ICalculator _calc;
}

Und Sie können die Bibliothek so einrichten, dass beim Erstellen ein Objekt in den Konstruktor eingefügt wird.

DI oder Dependency Injection bedeutet also, ein Objekt zu injizieren, das ein anderer benötigt.

32
Chad Moran

Dieser WilcoxTutorials-Typ bietet eine hervorragende Demonstration des Unity-Containers, der sich an Anfänger richtet.

Teil 1: http://www.youtube.com/watch?v=CWwe9Z0Gyew

Teil 2: http://www.youtube.com/watch?v=PsIbevgzQQE

In weniger als einer halben Stunde werden Sie die Grundlagen verstehen!

30
Ben Power

Die Einheit ist ein IoC. Der Sinn von IoC besteht darin, die Verknüpfung von Abhängigkeiten zwischen Typen außerhalb der Typen selbst zu abstrahieren. Dies hat einige Vorteile. Erstens erfolgt dies zentral, dh Sie müssen nicht viel Code ändern, wenn sich Abhängigkeiten ändern (was bei Komponententests der Fall sein kann).

Wenn für die Verkabelung Konfigurationsdaten anstelle von Code verwendet werden, können Sie die Abhängigkeiten nach der Bereitstellung neu verkabeln und so das Verhalten der Anwendung ändern, ohne den Code zu ändern.

9
Brian Rasmussen

MSDN verfügt über ein Entwicklerhandbuch für die Abhängigkeitsinjektion mit Unity , das möglicherweise hilfreich ist.

Das Entwicklerhandbuch beginnt mit den Grundlagen der Abhängigkeitsinjektion und enthält Beispiele für die Verwendung von Unity für die Abhängigkeitsinjektion. Ab Februar 2014 umfasst das Entwicklerhandbuch Unity 3.0, das im April 2013 veröffentlicht wurde.

5
Simon Tewsi

Ich beschreibe die meisten Beispiele für Abhängigkeitsinjektion in 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";
}

In DIAutoV2Controller.cs wird der Auto-Injection-Mechanismus verwendet

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

In DIV2Controller.cs wird alles von der Dependency Configuration Resolver-Klasse injiziert

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

Konfigurieren des Abhängigkeitsauflösers

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