Autofac-如何注册用作构造函数参数的类型,该类型要求将解析(构造函数)类型作为通用参数

时间:2018-12-13 13:40:04

标签: autofac

我有一个记录器类型ILogger。

对于在构造函数中需要ILogger的任何类型T,使用工厂方法Logger.For()创建ILogger的实例,该方法使用类型T作为通用参数。例如:

class Foo
{
    private ILogger logger;
    public Foo(Ilogger logger) 
    {
        this.logger = logger;
    }
}

public void Main()
{
    var foo = new Foo(Logger.For<Foo>());
}

有没有一种方法可以在Autofac中注册记录器工厂,以便从Logger.For()中自动为构造函数中具有ILogger参数的任何Autofac注册类型T提供实例?

1 个答案:

答案 0 :(得分:0)

有一个example of something like this in the Autofac docs使用log4net。代替Logger.For<T>()的是LogManager.GetLogger(typeof(T)),但是它成立了。

第一步将是找出给定的Type对象如何创建泛型方法调用。您可以这样做with MethodInfo.MakeGenericMethod.

类似...

private static object GetLogger(Type forType)
{
  // Get the LogManager.For<T>() method.
  var openMethod = typeof(LogManager).GetMethod("For", BindingFlags.Public | BindingFlags.Static);
  // Actually put the T in For<T>().
  var closedMethod = openMethod.MakeGenericMethod(forType);
  // Invoke the static method.
  return closedMethod.Invoke(null, null);
}

现在,您几乎可以立即使用该示例。

public class LoggingModule : Autofac.Module
{
  private static void InjectLoggerProperties(object instance)
  {
    var instanceType = instance.GetType();

    // Get all the injectable properties to set.
    // If you wanted to ensure the properties were only UNSET properties,
    // here's where you'd do it. Also, update the typeof() call/filter thing
    // here as needed.
    var properties = instanceType
      .GetProperties(BindingFlags.Public | BindingFlags.Instance)
      .Where(p => p.PropertyType == typeof(ILog) && p.CanWrite && p.GetIndexParameters().Length == 0);

    // Set the properties located.
    foreach (var propToSet in properties)
    {
      propToSet.SetValue(instance, LogManager.GetLogger(instanceType), null);
    }
  }

  private static void OnComponentPreparing(object sender, PreparingEventArgs e)
  {
    e.Parameters = e.Parameters.Union(
      new[]
      {
        // Again, update the check here to ensure you're only filling in the
        // right parameters.
        new ResolvedParameter(
            (p, i) => p.ParameterType == typeof(ILog),
            // Here's the call to that generic method.
            (p, i) => GetLogger(p.Member.DeclaringType)
        ),
      });
  }

  protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
  {
    // Handle constructor parameters.
    registration.Preparing += OnComponentPreparing;

    // Handle properties.
    registration.Activated += (sender, e) => InjectLoggerProperties(e.Instance);
  }

  private static object GetLogger(Type forType)
  {
    // Get the LogManager.For<T>() method.
    var openMethod = typeof(LogManager).GetMethod("For", BindingFlags.Public | BindingFlags.Static);
    // Actually put the T in For<T>().
    var closedMethod = openMethod.MakeGenericMethod(forType);
    // Invoke the static method.
    return closedMethod.Invoke(null, null);
  }
}

注意:我实际上还没有编译它。我有点赶不上头了。但这应该做到。

相关问题