Dot-Net

如何在 AutoFac 中創建可選依賴項?

  • March 25, 2022

我有一個介面、實現和目標:

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存在於載入外掛的主應用程序中。如果沒有載入 implementation 的外掛IPerson,Autofac 會因為無法解決Target的依賴關係而大發雷霆。我真的不能為此責備它。

但是我知道它Target能夠處理缺少的問題,IPerson並且很樂意得到 a null。事實上,我很確定所有依賴 an 的組件IPerson都準備好null取而代之了。那麼我怎麼能告訴 Autofac - “沒關係,親愛的,別擔心,給我一個null,好嗎?”

我發現的一種方法是將預設參數添加到Target

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 的空引用。另一種解決方案是創建NullPerson實現。

 builder.RegisterType<NullPerson>().As<IPerson>();
 builder.RegisterType<Target>();

當您的真實實現只再次註冊它時,它將覆蓋原始實現。

只需使用可選參數,請參見以下範例:

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

引用自:https://stackoverflow.com/questions/28415227