2017-08-15 1 views
0

Ich bin neu in Dependency Injection und entwickle eine App mit Xamarin.Forms, Prism und Unity. Soweit ich weiß, bei der Verwendung von DI wollen Sie liefern/injizieren Dienste für Klassen, damit sie sie nicht bekommen müssen. Dies führt zu Klassen, die keine Kenntnis von Service-Implementierungen haben.Kette von Abhängigkeiten mit Unity Dependency Injection und Xamarin.Forms

Das bedeutet, Constructor Injection anstelle des Containers zu verwenden, um die Dienste aufzulösen. Auch hier zu sehen http://structuremap.github.io/quickstart.

Mein Setup:

[assembly: Xamarin.Forms.Dependency(typeof(Foo))] 
public class Foo : IFoo 
{ 
    public IBar Bar { get; private set; } 

    public Foo(IBar bar) 
    { 
     Bar = bar; 
    } 
} 

[assembly: Xamarin.Forms.Dependency(typeof(Bar))]  
public class Bar : IBar 
{ } 

Nun, wenn ich IFoo eine Ausnahme zu lösen versuchen würde geworfen: System.MissingMethodException: Default constructor not found for type Foo Was ist hier los?

Ich habe auch versucht, einen leeren Konstruktor zu Foo hinzuzufügen, aber dies führt dazu, dass Bar null ist und zwingt mich, es vom IUnityContainer aufzulösen.

+1

Ihre letzte Bemerkung ist sehr verwirrend - wenn 'container.Resolve ()' Werke als Einheit sollten Bar in der Lage ganz gut ... –

+0

Einfache Antwort zu konstruieren - nicht Verwenden Sie Unity für neue Entwicklungen, da es sich um ein [totes Projekt] (https://stackoverflow.com/q/42722926) handelt und Sie sehr wahrscheinlich keine Unterstützung dafür erhalten. Verwenden Sie einen der [~ 35 anderen .NET DI-Container] (https://github.com/danielpalme/IocPerformance), die stattdessen aktiv verwaltet werden. – NightOwl888

+0

Das Problem scheint Ihre Registrierung zu sein, die alle Wörter ignoriert, die Sie verwendeten, es sieht aus, als ob Sie die Forms verwenden, die im Abhängigkeitsservice errichtet werden. Versuchen Sie, die Bar als Bar und nicht als Foo zu registrieren .... auch können wir streiten, bis die Kühe über Eigentum VS Konstruktor Injektion kommen, aber Sie können erreichen, was Sie beide Wege wollen – snowCrabs

Antwort

1

Grob gesagt, so weit ich sagen kann die Xamarin Formen Abhängigkeitsdienste (die es sieht wie Sie verwenden) bietet keine Konstruktorinjektion. Wenn Sie eine Konstruktor-basierte Injektion durchführen möchten, müssen Sie einen anderen Container-Service verwenden.

Wenn Sie die eingebauten Formulare verwenden, um die folgenden Änderungen an Ihrem Code Service sollte funktionieren ..

[assembly: Xamarin.Forms.Dependency(typeof(Foo))] 
public class Foo : IFoo 
{ 
public IBar Bar { get; set; } 

public Foo(IBar bar) 
{ 
    Bar = bar; 
} 
} 

[assembly: Xamarin.Forms.Dependency(typeof(Bar))]  
public class Bar : IBar 
{ } 

Dann wird Ihr Objekt-Set zu erhalten:

var myFoo = Xamarin.Forms.Dependency.Get<IFoo>(); 
    myFoo.Bar = Xamarin.Forms.Dependency.Get<IBar>(); 

Ansonsten möchten Sie vielleicht schau in ein anderes DI-Framework.

+0

Sie sind richtig :) es scheint, Xamarin erleichtert Dependency Injection nicht. Ich habe es am Ende gelöst, indem ich eine Basisklasse verwendet habe, und füge den Code als neue Antwort hinzu. –

0

Dank @snowCrabs habe ich gelernt, dass Xamarin.Forms Dependency Injection nicht erleichtert. Also entschied ich mich, eine Basisklasse zu erstellen, um Abhängigkeiten durch Reflektion auflösen zu können.

Meine Hauptmotivation für die Verwendung des Xamarin DependencyService ist, weil ich mag, wie Sie [assembly: Xamarin.Forms.Dependency(typeof(Foo))] verwenden können, um Ihre Klassen zu registrieren. Was bedeutet, dass ich in meinem App-Projekt keine Registrierung vornehmen muss. Ich muss nur einen Verweis auf mein Bibliotheksprojekt hinzufügen und der DependencyService wird es für mich registrieren, sodass ich die Schnittstelle sofort für die Verwendung auflösen kann.

Der Code:

public ServiceBase() 
{ 
    IEnumerable<PropertyInfo> dependencyProperties; 
    var dependencyAttribute = typeof(Microsoft.Practices.Unity.DependencyAttribute); 

    // DependencyService.Get<> requires a type parameter so we have to call it by using reflection 
    var dependencyServiceGet = typeof(DependencyService).GetRuntimeMethod("Get", new Type[] { typeof(DependencyFetchTarget) }); 

    // Get the properties from our derrived type (accessed by using "this") 
    dependencyProperties = this.GetType().GetTypeInfo().DeclaredProperties; 

    //Check if any properties have been tagged with the DependencyAttribute 
    dependencyProperties = dependencyProperties.Where(x => 
    { 
     return x.CustomAttributes.Any(y => y.AttributeType == dependencyAttribute); 
    }); 

    foreach (var prop in dependencyProperties) 
    { 
     // Add the type parameter to the Get-method 
     var resolve = dependencyServiceGet.MakeGenericMethod(prop.PropertyType); 

     // Now resolve the property via reflection: DependencyService.Get<PropertyType>(); 
     var service = resolve.Invoke(null, new object[] { DependencyFetchTarget.GlobalInstance }); 

     if (service == null) 
      throw new InvalidOperationException($"Herke.Forms.Core.ServiceBase: Dependency could not be resolved, did you forget to register?{Environment.NewLine}Type: {prop.PropertyType.FullName}{Environment.NewLine}Suggested code: \"[assembly: Dependency(typeof(>ImplementatingClass<))]\""); 

     // Fill property value 
     prop.SetValue(this, service); 
    } 
} 

[assembly: Xamarin.Forms.Dependency(typeof(Bar))]  
public class Bar : IBar 
{ } 

[assembly: Xamarin.Forms.Dependency(typeof(Foo))] 
public class Foo : ServiceBase, IFoo 
{ 
    [Microsoft.Practices.Unity.Dependency] 
    public IBar Bar { get; set; } 

    // Foo can use Bar now ! 
}