使用 Unity 依赖注入和 Xamarin.Forms 的依赖链
Chain of dependencies using Unity Dependency Injection and Xamarin.Forms
我是依赖注入的新手,我正在使用 Xamarin.Forms、Prism 和 Unity 开发应用程序。据我所知,在使用 DI 时,您希望 supply/inject 为 类 提供服务,这样他们就不必获取它们。导致 类 不了解服务实现。
这意味着使用构造函数注入而不是使用容器来解析服务。也看到这里 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 中解析它。
据我所知,粗略地说,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 框架。
感谢@snowCrabs,我了解到 Xamarin.Forms 不利于依赖注入。所以我决定做一个基础 class 来通过反射解决依赖关系。
我使用 Xamarin DepedencyService 的主要动机是因为我喜欢您可以使用 [assembly: Xamarin.Forms.Dependency(typeof(Foo))]
注册您的 classes 的方式。这意味着在我的 App 项目中,我不需要进行任何注册。我所要做的就是添加对我的库项目的引用,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 !
}
我是依赖注入的新手,我正在使用 Xamarin.Forms、Prism 和 Unity 开发应用程序。据我所知,在使用 DI 时,您希望 supply/inject 为 类 提供服务,这样他们就不必获取它们。导致 类 不了解服务实现。
这意味着使用构造函数注入而不是使用容器来解析服务。也看到这里 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 中解析它。
据我所知,粗略地说,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 框架。
感谢@snowCrabs,我了解到 Xamarin.Forms 不利于依赖注入。所以我决定做一个基础 class 来通过反射解决依赖关系。
我使用 Xamarin DepedencyService 的主要动机是因为我喜欢您可以使用 [assembly: Xamarin.Forms.Dependency(typeof(Foo))]
注册您的 classes 的方式。这意味着在我的 App 项目中,我不需要进行任何注册。我所要做的就是添加对我的库项目的引用,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 !
}