首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何获取被注入依赖项的类型?

如何获取被注入依赖项的类型?
EN

Stack Overflow用户
提问于 2020-03-06 04:59:46
回答 2查看 451关注 0票数 1

我正在使用.net Core2.2并使用依赖注入。我有一些自定义的基础设施依赖项,用于管理日志记录、跟踪等,我将它们注入到类中。我想让依赖项知道它们在哪个类中。如果我像new Logger<Type>();一样实例化这个类,我可以做到这一点,但这可以通过依赖注入来管理吗?

例如:

代码语言:javascript
复制
public class Logger<Type> : ILogger
{

}

public class Foo
{
    private Ilogger _logger;

    public Foo(ILogger logger)
    {
       _logger = logger;
    }

    public void DoStuff()
    {
        _logger.Log();  //<= knows it's in the Foo class.
    }
}

我如何将ILogger注入Foo,并让记录器知道它被注入到什么类型?

EN

回答 2

Stack Overflow用户

发布于 2020-03-06 05:17:44

您可以像这样指定类型

代码语言:javascript
复制
public class Foo
{
    private Ilogger<Foo> _logger;
}

然后在记录器中,您可以通过以下方式了解T的类型

代码语言:javascript
复制
public class Logger<T> : ILogger<T>
{
    public Type WhatType() => typeof(T);
}

您需要像这样注册服务

代码语言:javascript
复制
serviceCollection.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
票数 1
EN

Stack Overflow用户

发布于 2020-03-07 00:36:28

虽然更成熟和功能丰富的DI容器,如AutofacSimple Injector,确实支持基于上下文的注入(这是您正在寻找的功能),但MS.DI不支持此功能。

正是由于这个原因,所有微软文档都描述了在T等于消费类型的情况下注入通用ILogger<T>,例如:

代码语言:javascript
复制
public class C
{
    public C(ILogger<C> logger) { ... }
}

然而,让消费者依赖通用ILogger<T>,而不是简单地依赖非通用ILogger,会更加冗长且容易出错。这会让你的代码更难测试,更难维护。这可能是您尝试注入上下文感知ILogger的原因,我为此而鼓掌。

您可以通过迭代ServiceCollection将此功能“黑”到MS.DI中,但实际上它有太多的限制,无法在您的生产应用程序中使用。然而,为了好玩和娱乐,你可以尝试这样做:

代码语言:javascript
复制
// Run just before finalizing the IServiceCollection
for (int i = 0; i < services.Count; i++)
{
    ServiceDescriptor descriptor = services[i];

    if (descriptor.ImplementationType != null)
    {
        var loggerParameters =
            from ctor in descriptor.ImplementationType.GetConstructors()
            from param in ctor.GetParameters()
            where param.ParameterType == typeof(ILogger)
            select param;

        if (loggerParameters.Any())
        {
            // Replace registration
            services[i] =
                new ServiceDescriptor(
                    descriptor.ServiceType,
                    provider =>
                        ActivatorUtilities.CreateInstance(
                            provider,
                            descriptor.ImplementationType,
                            provider.GetRequiredService(
                                typeof(ILogger<>).MakeGenericType(
                                    descriptor.ImplementationType))),
                    descriptor.Lifetime);
        }
    }
}

这段代码的作用是:

  • 搜索使用自动连接的
    • (关闭或非泛型)实现类型
    • 的注册(因此没有lambda注册,或者其构造函数依赖于ILogger

的实例registration)

  • and

  • 并将该注册替换为lambda注册,该注册将自动连接类型(使用ActivatorUtilities),同时将ILogger依赖项替换为ILogger<T>依赖项。

限制:

当用另一个DI容器替换registrations

  • Doesn't时,
  • 在开放的通用registrations
  • Doesn‘t上不工作,在委托registrations
  • Might上不工作(例如,当使用多个container).
  • Behavior时,MS.DI可能是未定义的

因此,在实践中,我不建议使用这种方法,而是使用成熟的DI Container。

提示:为了获得一些灵感,在使用Simple Injector时,可以按如下方式进行基于上下文的注册:

代码语言:javascript
复制
container.RegisterConditional(
    typeof(ILogger),
    c => typeof(Logger<>).MakeGenericType(c.Consumer.ImplementationType),
    Lifestyle.Singleton,
    c => true);

当与ASP.NET核心集成时,简单注入器甚至包含一个扩展方法来简化这一点。Here关于如何配置容器以注入ASP.NET核心的ILogger的简单注入器文档,以及关于如何在简单注入器中应用基于上下文的注入的基本描述可以在here中找到。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60553855

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档