如何包装功能Func <ISomething,T>委托

时间:2019-09-10 06:37:15

标签: c# delegates autofac func

我想使用 Func 作为方法参数包装一个库,而 ISomething 是该库的一部分。 我的包装器应该具有对库的所有引用,并且使用包装器的人不必引用该库。

我想包装Autofac Register方法(带有lambda表达式),例如此处https://autofaccn.readthedocs.io/en/latest/register/registration.html#lambda-expression-components

我某种程度上需要转换

Func<IDependencyContainer, T> delegate1

Func<IComponentContext, T> delegate1

这是我当前的尝试样子:

public IDependencyContainerToAddOptions<T> WrapperRegister<T>
(
  Func<IDependencyContainer, T> delegate1
)
{
  return new DependencyContainerToAddOptions<T>(_containerBuilder.Register(delegate1));
}

TLDR:

如何包装Autofac的Register方法,可以这样调用:

  _builder.Register(ctx =>
        { var profileService = ctx.Resolve<IUserProfileService>();

,其定义如下:

/// <summary>
/// Register a delegate as a component.
/// </summary>
/// <typeparam name="T">The type of the instance.</typeparam>
/// <param name="builder">Container builder.</param>
/// <param name="delegate">The delegate to register.</param>
/// <returns>Registration builder allowing the registration to be configured.</returns>
public static IRegistrationBuilder<T, SimpleActivatorData, SingleRegistrationStyle>
    Register<T>(
        this ContainerBuilder builder,
        Func<IComponentContext, T> delegate1)
{
    if (delegate1 == null) throw new ArgumentNullException(nameof(delegate1));

    return builder.Register((c, p) => delegate1(c));
}

包装程序的用户不必向Autofac添加依赖项。

1 个答案:

答案 0 :(得分:1)

您尝试做的事情似乎与this FAQ in the Autofac docs asking how to keep Autofac references out of your app.有很多重叠,特别是,您在问如何有效地复制Autofac的某些注册语法,我想这样您的应用程序就可以注册内容而无需引用Autofac。

这样做有很多充分的理由,但是我可能会说服您不要这样做。如该常见问题解答所述:

  

您可能会花费大量时间来编写事物的抽象和包装,而只是复制许多特定于Autofac的语法和功能。

这种“将自己与引用隔离”的情况在日志记录中也经常发生,而且也没有很多超好的解决方案。

随着.NET Core的出现,一种方法是使用Microsoft.Extensions.DependencyInjection抽象。使用IServiceCollection在此处注册内容,然后即可使用the Autofac.Extensions.DependencyInjection package to push those registrations into an Autofac container。这限制了您对抽象的支持,但是却为您提供了不必维护的抽象。

但是,再说一次,您确实要维护自己的。如果您想让人们注册Func<IComponentContext, T>,那么您应该意识到IComponentContext是Autofac的事情,这打破了您的孤立感。您在底部的更新中提到,希望您的用户不要引用Autofac ...,但是再次考虑,您需要镜像所有Autofac的行为和语法。

因此,如果要执行此操作,则需要创建包装器和抽象。很多包装和抽象。超过将值得维护。该模式将是:

  • 创建一个界面,该界面公开您要提供给客户的功能。
  • 创建一个包装Autofac内容并实现接口的包装器/代理类。
  • 在合成根目录(例如,应用启动等)中包装Autofac实施并完成所有工作。

类似的东西:

public interface IMyComponentContext
{
  T Resolve<T>();
}
public class ComponentContextWrapper : IMyComponentContext
{
  private readonly IComponentContext _autofacContext;
  public ComponentContextWrapper(IComponentContext autofacContext)
  {
    _autofacContext = autofacContext;
  }
  public T Resolve<T>()
  {
    return this._autofacContext.Resolve<T>();
  }
}

将会很多。然后...

  • IComponentContext创建一个包装器。
  • 为所有注册位创建包装器。
  • 基本上已经实现了那里的功能-除非您需要根据需要包装/解包。像这样:
// In the place where you actually register your delegates, you'll have
// to provide wrappers for your clients:
builder.Register((c, p) => delegate1(new ComponentContextWrapper(c)));

如果我还没有说清楚的话,我强烈认为这是一个坏主意。这是很多工作,除非真的有一些潜在的需求要离开Autofac,否则维护抽象,测试抽象等没有真正的收获。但是,如果要保持这种分离,这就是您需要做的。祝你好运!