我有一个接口,实现和目标:
public interface IPerson { public string Name { get; } } public class Person: IPerson { public string Name { get { return "John"; } } } public class Target { public Target(IPerson person) {} }
我正在使用Autofac将事物联系在一起:
builder.RegisterType<Person>().As<IPerson>().SingleInstance();
问题是IPerson生活在一个共享程序集中,Person存在于一个插件中(可能存在也可能不存在),而Target存在于加载插件的主应用程序中.如果没有加载实现IPerson的插件,Autofac就无法解决Target的依赖关系而犹豫不决.我不能真的责怪它.
但是我知道Target能够处理缺少IPerson而且非常乐意获得null.事实上,我非常确定依赖于IPerson的所有组件都准备好取而代之.那么我怎么能告诉Autofac-“这是好的,不要担心,只要给我一个空的,好吗?”
public class Target { public Target(IPerson person = null) {} }
这有效,但我需要为所有需要IPerson的组件执行此操作.我可以反过来做吗?不知何故告诉Autofac“如果所有其他方法都无法解析IPerson,请返回null”?
您可以使用以下语法:
builder.RegisterType<Target>().WithParameter(TypedParameter.From<IPerson>(null));
不幸
builder.Register(c => (IPerson)null).As<IPerson>(); // will throw : Autofac.Core.DependencyResolutionException: A delegate registered to create instances of 'ConsoleApplication17.Program+IPerson' returned null.
和
builder.RegisterInstance<IPerson>(null).As<IPerson>(); // will throw : Unhandled Exception: System.ArgumentNullException: Value cannot be null.
如果您不想为每个注册添加WithParameter,则可以添加一个可以为您执行此操作的模块
public class OptionalAutowiringModule : Autofac.Module { public OptionalAutowiringModule(IEnumerable<Type> optionalTypes) { this._optionalTypes = optionalTypes; } public OptionalAutowiringModule(params Type[] optionalTypes) { this._optionalTypes = optionalTypes; } private readonly IEnumerable<Type> _optionalTypes; protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry,IComponentRegistration registration) { base.AttachToComponentRegistration(componentRegistry,registration); registration.Preparing += (sender,e) => { e.Parameters = e.Parameters.Concat(new Parameter[] { new OptionalAutowiringParameter(this._optionalTypes) }); }; } } public class OptionalAutowiringParameter : Parameter { public OptionalAutowiringParameter(IEnumerable<Type> optionalTypes) { this._optionalTypes = optionalTypes.ToList(); } private readonly List<Type> _optionalTypes; public override Boolean CanSupplyValue(ParameterInfo pi,IComponentContext context,out Func<Object> valueProvider) { if (this._optionalTypes.Contains(pi.ParameterType) && !context.IsRegistered(pi.ParameterType)) { valueProvider = () => null; return true; } else { valueProvider = null; return false; } } }
然后,您所要做的就是使用可选的依赖项注册模块
builder.RegisterModule(new OptionalAutowiringModule(typeof(IPerson)));
但不是注入可能导致nullReferenceException的null引用.另一种解决方案是创建NullPerson实现.
builder.RegisterType<NullPerson>().As<IPerson>(); builder.RegisterType<Target>();
如果您的实际实现仅重新注册,它将覆盖原始实现.