【问题标题】:How to Wrap a Function Func<ISomething,T> delegate如何包装函数 Func<ISomething,T> 委托
【发布时间】:2019-09-10 06:37:15
【问题描述】:

我想使用 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。

【问题讨论】:

  • 不确定我是否理解正确,您只是想将 Register 方法包装到委托中?
  • 不,我想从 Autofac 包装这个函数:_builder.Register(ctx =&gt; { var profileService = ctx.Resolve&lt;IUserProfileService&gt;();
  • 我编辑了我的问题以使其更易于理解。
  • 这部分不清楚:“使用包装器的人应该不需要引用库。”如果我理解正确,您的意思是包含ISomething 的库。但是您可以在不引用接口的情况下注册接口的实现。您能澄清一下您要完成的工作吗?有些东西涉及包装注册函数以注册代表here。这些有帮助吗?
  • -“使用包装器的人不需要引用库。” - 你的意思是包含 ISomething 的库? -是的。我尝试了“在不引用接口的情况下注册接口的实现”,但它不起作用:` public void WrappedRegister (Func delegate1) { builder.Register(delegate1); } 公共类 TheComponentContext: IComponentContext {...`

标签: c# delegates autofac func


【解决方案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&lt;IComponentContext, T&gt;,那么您应该意识到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,否则维护抽象、测试它们等并没有真正的回报。但是,如果你想保持这种分离,这就是你需要做的。祝你好运!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    相关资源
    最近更新 更多