2017-08-15 72 views
0

我是依賴注入的新手,我正在開發一個使用Xamarin.Forms,Prism和Unity的應用程序。所以據我所知,在使用DI時,您希望向課程提供/注入服務,以便他們不必獲取它們。導致不瞭解服務實現的類。使用Unity Dependency Injection和Xamarin.Forms的依賴項鍊

這意味着使用構造函數注入而不是使用Container來解析服務。也看到這裏http://structuremap.github.io/quickstart

我的設置:

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

現在,如果我會盡力解決的IFoo拋出一個異常:System.MissingMethodException: Default constructor not found for type Foo 這到底是怎麼回事?

我也嘗試向Foo添加一個空的構造函數,但這會導致Bar爲null,並迫使我從IUnityContainer中解析它。

+1

你的最後一句話是非常混亂 - 如果'container.Resolve ()'作品比團結應該能夠構建酒吧就好了... –

+0

答案很簡單 - 不使用Unity進行新開發是因爲它是[dead project](https://stackoverflow.com/q/42722926),你不太可能獲得任何支持。使用其中一個正在積極維護的[〜35其他.NET DI容器](https://github.com/danielpalme/IocPerformance)。 – NightOwl888

+0

問題似乎是您的註冊忽略了您使用的所有單詞,它看起來像您正在使用內置在依賴項服務中的表單。嘗試註冊酒吧作爲酒吧,而不是作爲一個富...也可以爭論,直到奶牛回家的屬性VS構造注入,但你可以實現你想要的兩種方式 – snowCrabs

回答

1

粗略地說,據我可以告訴Xamarin表單依賴服務(它看起來像你正在使用)不提供構造函數注入。所以如果你想做基於構造函數的注入,你將需要使用不同的容器服務。

,如果你想使用內置的服務形式以下更改您的代碼應該工作..

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

然後讓你的對象集:

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

否則,你可能想看看另一個DI框架。

+0

你是對的:)它似乎Xamarin不利於依賴注入。我最終通過使用一個基類來解決這個問題,並且把代碼添加爲新的答案。 –

0

感謝@snowCrabs,我瞭解到Xamarin.Forms不利於依賴注入。所以我決定創建一個基類來啓用通過反射來解析依賴關係。

我使用Xamarin DepedencyService的主要動機是因爲我喜歡使用[assembly: Xamarin.Forms.Dependency(typeof(Foo))]來註冊類的方式。這意味着在我的應用程序項目中,我不必進行任何註冊。我所要做的就是添加一個對我的庫項目的引用,DependencyService將爲我註冊它,使我能夠立即解決接口的使用問題。

代碼:

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 ! 
}