如何在使用反射创建实例时传递记录器 object?

How to pass logger object while creating instance using reflection?

摘要Class:

public abstract class Rater
{
    public Rater()
    {
    }
    public abstract decimal Rate(Policy policy);
}

Child classes:

public class AutoPolicyRater : Rater
{
        public readonly ILogger<AutoPolicyRater> _logger;
        
        public AutoPolicyRater(ILogger<AutoPolicyRater> logger)
        { 
            _logger = logger;
        }

        public override decimal Rate(Policy policy)
        {
            _logger.Log("Rating AUTO policy...");
            _logger.Log("Validating policy.");
            if (String.IsNullOrEmpty(policy.Make))
            {
                _logger.Log("Auto policy must specify Make");
                return 0m;
            }
            if (policy.Make == "BMW")
            {
                if (policy.Deductible < 500)
                {
                   
                    return 1000m;
                }
                return 900m;
            }
            return 0m;
        }
}

public class LandPolicyRater : Rater
{

        public readonly ILogger<LandPolicyRater> _logger;
        
        public AutoPolicyRater(ILogger<LandPolicyRater> logger)
        { 
            _logger = logger;
        }

        public override decimal Rate(Policy policy)
        {
            _logger.Log("Rating LAND policy...");
            _logger.Log("Validating policy.");
            if (policy.BondAmount == 0 || policy.Valuation == 0)
            {
                _logger.Log("Land policy must specify Bond Amount and Valuation.");
                return 0m;
            }
            if (policy.BondAmount < 0.8m * policy.Valuation)
            {
                _logger.Log("Insufficient bond amount.");
                return 0m;
            }
            return (policy.BondAmount * 0.05m);
        }
}

工厂class,我想动态传递记录器的地方object:

public class RaterFactory
{
    private readonly IRatingUpdater _ratingUpdater;
    

    public RaterFactory(ILogger logger)
    {
    
    }
    public Rater Create(Policy policy)
    {
        try
        {
            return (Rater)Activator.CreateInstance(
                Type.GetType($"MyCompany.{policy.Type}PolicyRater"),
                new object[] { ?? });//here I want to pass logger object
        }
        catch
        {
            return new UnknownPolicyRater();
        }
    }
}

由于这些 class 不是控制器,我想在我的工厂方法中创建 object,我如何将记录器 object 和日志信息传递给 application insight?我想通过通用记录器object,但是,如果有另一种方法可以实现,我没问题。

编辑:

根据@fildor 的建议,我在下面进行了尝试,它正在 Application Insight 跟踪中记录信息。

public class RaterFactory
{
    private readonly ILoggerFactory _loggerFactory;

    public RaterFactory(ILoggerFactory loggerFactory)
    {
        _loggerFactory = loggerFactory;
    }

    public Rater Create(Policy policy)
    {
        try
        {
            string typeString = $"MyCompany.{policy.Type}PolicyRater";

            ILogger modelLogger = _loggerFactory.CreateLogger(typeString);

            return (Rater)Activator.CreateInstance(
                Type.GetType($"MyCompany.{policy.Type}PolicyRater"),
                new object[] { modelLogger });
        }
        catch
        {
            return new UnknownPolicyRater();
        }
    }
}
public class AutoPolicyRater : Rater
{
        public readonly ILogger _logger;
        
        public AutoPolicyRater(ILogger logger)
        { 
            _logger = logger;
        }
       //other code
}

根据要求:可能的实现:

public class RaterFactory
{
    private readonly ILoggerFactory _loggerFactory;

    public RaterFactory(ILoggerFactory loggerFactory)
    {
        _loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
    }

    public Rater Create(Policy policy)
    {
        try
        {
            return (Rater)Activator.CreateInstance(
                Type.GetType($"MyCompany.{policy.Type}PolicyRater"),
                new object[] { _loggerFactory });
        }
        catch
        {
            return new UnknownPolicyRater();
        }
    }
}

然后...

public class AutoPolicyRater : Rater
{
        private readonly ILogger<AutoPolicyRater> _logger;
        
        public AutoPolicyRater(ILoggerFactory loggerFactory)
        { 
            _logger = loggerFactory.CreateLogger<AutoPolicyRater>();
        }

        public override decimal Rate(Policy policy)
        {
            // ... ommited for brevity
        }
}

RaterFactory class 不需要事先知道注入到它创建的实例中的所有依赖项。

相反,您可以注入 IServiceProvider 并让 ActivatorUtilities 解析您每次创建的 Rater 个实例的依赖关系。

这是可以做到的:

public class RaterFactory
{
    private readonly IServiceProvider _serviceProvider;

    public RaterFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public Rater Create(Policy policy)
    {
        try
        {
            // OPTION 1
            return (Rater)ActivatorUtilities.CreateInstance(
                _serviceProvider,
                Type.GetType($"MyCompany.{policy.Type}PolicyRater"));

            // OPTION 2
            return (Rater)ActivatorUtilities.GetServiceOrCreateInstance(
                _serviceProvider,
                Type.GetType($"MyCompany.{policy.Type}PolicyRater"));
        }
        catch
        {
            return new UnknownPolicyRater();
        }
    }
}

如上所示,您应该根据自己的需要和限制选择两个可能的选项。

  1. ActivatorUtilities.CreateInstance:此方法每次创建一个新实例并且不查询目标类型的服务集合。如果您事先不知道所有可能的目标类型(或者您出于某种原因不想注册它们),这会很方便。
  2. ActivatorUtilities.GetServiceOrCreateInstance:该方法在服务集合中查找目标类型;如果找到注册,则它 returns 对应的实例,否则它的行为类似于 ActivatorUtilities.CreateInstance。这意味着您可以像往常一样在服务集合中注册目标类型,并为每种类型设置最合适的生命周期(单例、作用域或瞬态)。这种方法的唯一缺点是,如果您有一些单例或作用域目标类型,您必须提供一种方法将它们注册到服务集合中,这在 plugin-like 应用程序中可能很棘手。

再次请注意,在 Rater 子类型中可以注入哪些依赖项没有任何限制,因为毕竟依赖项解析的“脏”工作是由 ActivatorUtilities class.