Autofac - 如何在创建实例时获取 class 名称

Autofac - How to get class name while creating instance

我对 Autofac 有疑问: 如何从容器中获取 class 请求实例的名称?

是否可以在创建对象时获取由 autofac 传递给构造函数的 class "Autofac_Test" 的名称?

我的代码:

using System;
using System.Diagnostics;
using System.Reflection;
using Autofac;
using Xunit;

public class BootStrap
{
    public IContainer Configure()
    {
        var builder = new ContainerBuilder();
        builder.Register(b => new MyLogger(MethodBase.GetCurrentMethod().ReflectedType)).As<ILog>();
        return builder.Build();
    }
}
public class Autofac_Test
{
    private IContainer _containter;
    public Autofac_Test()
    {
        _containter = new BootStrap().Configure();
    }
    [Fact]
    public void Should_create_class_with_Name_BlaBla()
    {
        var logger = _containter.Resolve<ILog>();
        Assert.True(logger.Name == "Autofac_Test");
    }
}
public class MyLogger : ILog
{
    public string Name { get; private set; }
    public MyLogger(Type name)
    {
        Name = name.FullName;
    }
    public void Info(string message)
    {
        Debug.WriteLine(string.Format("{0} {1}", Name, message));
    }
}

public interface ILog
{
    void Info(string message);
    string Name { get; }
}

更新

@Cyril Durand 已经证明了这是可能的。下面的建议仍然是正确的,但不是那么好。

autofac 好像不支持你想要的。您当然可以在 MyLogger 构造函数中解析调用堆栈,但这会降低性能。

已经有一个关于非常相似的事情的问题,建议改为工厂

Autofac. Register class with constructor with params

对于您的具体情况,获取此信息将相当困难。但据我了解这个问题,MyLogger 需要知道它将被注入的类型名称,代码示例可能不相关。

在这种情况下,您可以使用模块和 Preparing 事件:

public class LoggingModule : Autofac.Module
{
    protected override void AttachToComponentRegistration(
        IComponentRegistry componentRegistry, IComponentRegistration registration)
    {
        registration.Preparing += (sender, e) =>
        {
            Type limitType = e.Component.Activator.LimitType;
            e.Parameters = e.Parameters.Union(new[] {
                new ResolvedParameter((pi, c) => pi.ParameterType == typeof(ILogger), 
                                      (pi, c) => c.Resolve<ILogger>(new NamedParameter("name", limitType.Name))),
            });
        };
    }
}

然后你必须像这样注册你的模块:

ContainerBuilder builder = new ContainerBuilder();
builder.RegisterModule<LoggingModule>();
builder.RegisterType<MyLogger>().As<ILogger>();

现在每次将 ILogger 注入一个类型时,它都会有正确的名称。

class Foo
{
    public Foo(ILogger logger)
    {
        this._loggerName = logger.Name;
    }

    private readonly String _loggerName; 

    public String LoggerName 
    {
        get 
        {
            return this._loggerName;
        }
    }
}

LoggerName 将是 Foo

您的测试现在看起来像这样:

[Fact]
public void Should_create_class_with_Name_BlaBla()
{
    var foo = _containter.Resolve<Foo>();
    Assert.AreEquals("foo", foo.LoggerName, "invalid loggerName");
}