如何包装函数 Func<ISomething,T> 委托

How to Wrap a Function Func<ISomething,T> delegate

我想使用 Func < T , ISomething > 作为方法参数包装一个库,其中 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 添加依赖项。

看起来你正在尝试做的事情与 this FAQ in the Autofac docs asking how to keep Autofac references out of your app. 有很多重叠,特别是,你问的是如何有效地复制 Autofac 的一些注册语法,我猜这样你的应用程序就可以注册东西不引用 Autofac。

这样做有一些很好的理由,但我可能会试图说服你不要这样做。如该常见问题解答中所述:

You will potentially sink a lot of time into writing abstractions and wrappers around things only to replicate a lot of Autofac-specific syntax and capabilities.

同样的 "isolate oneself from references" 也经常发生在日志记录中,而且也没有很多超级好的解决方案。

随着 .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 行为和语法。

因此,如果您要这样做,则需要创建包装器和抽象。很多包装器和抽象。不仅值得维护。模式将是:

  • 创建一个界面,公开您要为客户提供的功能。
  • 创建一个 wrapper/proxy class 来包装 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 创建包装器。
  • 为所有注册位创建包装器。
  • 基本上已经实现了上面的内容 - 除非您需要 wrap/unwrap 根据需要。类似于:
// 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,否则维护抽象、测试它们等并没有真正的回报。但是,如果你想保持这种分离,那就是你需要做的。祝你好运!