如何在AutoFac中创建可选的依赖项?

Vil*_*lx- 9 .net default-value autofac

我有一个接口,实现和目标:

public interface IPerson { public string Name { get; } }
public class Person: IPerson { public string Name { get { return "John"; } } }
public class Target { public Target(IPerson person) {} }
Run Code Online (Sandbox Code Playgroud)

我正在使用Autofac将事物联系在一起:

builder.RegisterType<Person>().As<IPerson>().SingleInstance();
Run Code Online (Sandbox Code Playgroud)

问题是IPerson生活在共享程序Person集中,存在于插件中(可能存在也可能不存在),并且Target存在于加载插件的主应用程序中.如果没有加载该插件的插件IPerson,Autofac就无法解决Target依赖关系而犹豫不决.我不能真的责怪它.

但是我知道Target能够处理缺乏的东西IPerson而且很乐意得到一个null代替.事实上,我很确定所有依赖于它的组件IPerson都准备好null了.那么我怎么能告诉Autofac-"这很好,不要担心,只要给我一个null,好吗?"

我找到的一种方法是将默认参数添加到Target:

public class Target { public Target(IPerson person = null) {} }
Run Code Online (Sandbox Code Playgroud)

这是有效的,但我需要为所有需要的组件执行此操作IPerson.我可以反过来做吗?不知何故告诉Autofac"如果所有其他方法都无法解析IPerson,则返回null"?

Yas*_*adi 8

只需使用可选参数,请参阅以下示例:

public class SomeClass
{
     public SomeClass(ISomeDependency someDependency = null)
     {
           // someDependency will be null in case you've not registered that before, and will be filled whenever you register that.
     }
}
Run Code Online (Sandbox Code Playgroud)


Cyr*_*and 5

您可以使用以下语法:

  builder.RegisterType<Target>().WithParameter(TypedParameter.From<IPerson>(null));
Run Code Online (Sandbox Code Playgroud)

不幸

  builder.Register(c => (IPerson)null).As<IPerson>();
  // will throw : Autofac.Core.DependencyResolutionException: A delegate registered to create instances of 'ConsoleApplication17.Program+IPerson' returned null.
Run Code Online (Sandbox Code Playgroud)

  builder.RegisterInstance<IPerson>(null).As<IPerson>();
  // will throw : Unhandled Exception: System.ArgumentNullException: Value cannot be null.
Run Code Online (Sandbox Code Playgroud)

如果您不想为每个注册添加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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您所要做的就是使用可选的依赖项注册模块

builder.RegisterModule(new OptionalAutowiringModule(typeof(IPerson)));
Run Code Online (Sandbox Code Playgroud)

但不是注入可能导致nullReferenceException的null引用.另一种解决方案是创建NullPerson实现.

  builder.RegisterType<NullPerson>().As<IPerson>();
  builder.RegisterType<Target>();
Run Code Online (Sandbox Code Playgroud)

如果您的实际实现仅重新注册,它将覆盖原始实现.