如何在内置依赖注入中使用Func <T>

Lui*_*ipe 8 dependency-injection asp.net-core

使用asp.net 5我喜欢我的控制器注入Func<T>而不是T

例如:

public HomeController(Func<Interfaces.IUnitOfWork> uow)
Run Code Online (Sandbox Code Playgroud)

代替

public HomeController(Interfaces.IUnitOfWork uow)
Run Code Online (Sandbox Code Playgroud)

是否可以使用内置DI或我被迫移动到外部DI?

Pau*_*les 8

Func<T> 默认情况下没有注册或解决,但没有什么能阻止您自己注册.

例如

services.AddSingleton(provider => 
  new Func<IUnitOfWork>(() => provider.GetService<IUnitOfWork>()));
Run Code Online (Sandbox Code Playgroud)

请注意,您还需要以通常的方式注册IUnitOfWork.

  • 这应该是最重要的答案。您还可以像这样缩短它: services.AddSingleton&lt;Func&lt;IUnitOfWork&gt;&gt;(x =&gt; () =&gt; x.GetService&lt;IUnitOfWork&gt;()); (4认同)

Sco*_*nen 7

您可以Func<T>使用 注册一个或一个代表ServiceCollection。我推荐使用委托,因为它允许您区分具有相同签名的不同方法。

这是一个例子。

public interface IThingINeed {}
public class ThingINeed : IThingINeed { }

public delegate IThingINeed ThingINeedFactory();

public class DelegateRegistrationTests
{
    [Test]
    public void RegisterDelegateFromDependency()
    {
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddTransient<IThingINeed, ThingINeed>();
        serviceCollection.AddTransient<ThingINeedFactory>(
            provider => provider.GetService<IThingINeed>);
        var serviceProvider = serviceCollection.BuildServiceProvider();
        var factoryMethod = serviceProvider.GetService<ThingINeedFactory>();
        var output = factoryMethod();
        Assert.IsInstanceOf<ThingINeed>(output);
    }
}
Run Code Online (Sandbox Code Playgroud)

这几乎看起来像一个服务定位器,因为我们正在解析的函数实际上是IServiceCollection.GetService<ThingINeedFactory>(). 但这隐藏在组合根中。注入此委托的类取决于委托,而不是实现。

如果要返回的方法属于容器必须解析的类,则可以使用相同的方法。

public interface IThingINeed
{
    string SayHello();
}

public class ThingINeed : IThingINeed
{
    private readonly string _greeting;

    public ThingINeed(string greeting)
    {
        _greeting = greeting;
    }

    public string SayHello() => _greeting;
}

public class ThingINeedFactory
{
    public IThingINeed Create(string input) => new ThingINeed(input);
}

public delegate IThingINeed ThingINeedFactoryMethod(string input);

public class DelegateRegistrationTests
{
    [Test]
    public void RegisterDelegateFromDependency()
    {
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddSingleton<IThingINeed, ThingINeed>();
        serviceCollection.AddSingleton<ThingINeedFactory>();
        serviceCollection.AddSingleton<ThingINeedFactoryMethod>(provider => 
            provider.GetService<ThingINeedFactory>().Create);
        var serviceProvider = serviceCollection.BuildServiceProvider();
        var factoryMethod = serviceProvider.GetService<ThingINeedFactoryMethod>();
        var created = factoryMethod("abc");
        var greeting = created.SayHello();
        Assert.AreEqual("abc", greeting);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个扩展方法(也许)使它变得更容易一些:

public static class ServiceCollectionExtensions
{
    public static IServiceCollection RegisterDelegate<TSource, TDelegate>(
        this IServiceCollection serviceCollection,
        Func<TSource, TDelegate> getDelegateFromSource) 
            where TDelegate : class 
    {
        return serviceCollection.AddSingleton(provider =>
            getDelegateFromSource(provider.GetService<TSource>()));
    }
}

serviceCollection
    .RegisterDelegate<ThingINeedFactory, ThingINeedFactoryMethod>(
        factory => factory.Create);
Run Code Online (Sandbox Code Playgroud)


Jos*_*ard 5

据我所知,使用 ASP.NET Core 中当前默认的 IoC 容器不可能延迟这样的依赖关系。无论如何我都没能让它工作!

要推迟像这样的依赖项的初始化,您需要实现一个现有的、功能更丰富的 IoC 容器。


Mar*_*ndl 5

我写了一个注册服务和工厂的小扩展方法Func<T>( ):

public static class IServiceCollectionExtension
{
    public static IServiceCollection AddFactory<TService, TServiceImplementation>(this IServiceCollection serviceCollection) 
        where TService : class
        where TServiceImplementation : class, TService
    {
        return serviceCollection
            .AddTransient<TService, TServiceImplementation>();
            .AddSingleton<Func<TService>>(sp => sp.GetRequiredService<TService>);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法

serviceCollection
   .AddFactory<IMyInterface, MyImplementation>()
Run Code Online (Sandbox Code Playgroud)