解析数组时,Autofac会发出意外的Component.Target.Activator.LimitType

时间:2015-05-13 19:32:30

标签: c# autofac

当我解析数组时,有人可以解释为什么Component.Target.Activator.LimitType显示Meta<Lazy<IFoo>>[]而不是预期的Foo?这是Autofac中的错误吗?如何获得预期的限制类型= Foo

这是一个使用Autofac 3.5.2和.Net 4.5的完整程序:

static class Program
{
    static void Main()
    {
        var builder = new ContainerBuilder();
        builder.RegisterModule<ALoggerModule>();
        builder.RegisterType<Foo>()
            .As<IFoo>();
        var container = builder.Build();

        Debug.WriteLine("Resolving Meta<Lazy<IFoo>>[]");
        var metafoos = container.Resolve<Meta<Lazy<IFoo>>[]>();
        foreach (var metalazyfoo in metafoos)
        {
            Debug.WriteLine("\tResult is: ".PadRight(39) + metalazyfoo.Value.Value.TheALogger.LimitType);
        }

        Debug.WriteLine("Resolving Meta<Lazy<IFoo>>");
        var secondmetalazyfoo = container.Resolve<Meta<Lazy<IFoo>>>();
        Debug.WriteLine("\tResult is: ".PadRight(39) + secondmetalazyfoo.Value.Value.TheALogger.LimitType);
        Debug.WriteLine("Done");
    }

    public static string GetPrettyName(this Type type)
    {
        if (type.IsGenericType)
        {
            var genargNames = type.GetGenericArguments().Select(GetPrettyName);
            var idx = type.Name.IndexOf('`');
            var typename = (idx > 0) ? type.Name.Substring(0, idx) : type.Name;

            return String.Format("{0}<{1}>", typename, String.Join(", ", genargNames));
        }
        else if (type.IsArray)
        {
            return String.Format("{0}[]", GetPrettyName(type.GetElementType()));
        }

        return type.Name;
    }
}



public interface IFoo
{
    ALogger TheALogger { get; }
}


public class Foo : IFoo
{
    public ALogger TheALogger { get; private set; }

    public Foo(ALogger aLogger) { TheALogger = aLogger; }
}


public class ALogger
{
    public string LimitType { get; private set; }

    public ALogger(string limitType)
    {
        LimitType = limitType;
    }
}

public class ALoggerModule : Autofac.Module
{
    protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
    {
        registration.Preparing += (sender, args) =>
        {
            args.Parameters = args.Parameters.Union(new[]
            {
                new ResolvedParameter(
                    predicate: (p, i) => p.ParameterType == typeof(ALogger), 
                    valueAccessor: (p, i) =>
                    {
                        Debug.WriteLine(String.Format("\tComponent.Activator.LimitType:        {0}", args.Component.Activator.LimitType.GetPrettyName()));
                        Debug.WriteLine(String.Format("\tComponent.Target.Activator.LimitType: {0}", args.Component.Target.Activator.LimitType.GetPrettyName()));
                        return new ALogger(args.Component.Target.Activator.LimitType.GetPrettyName());
                    })
            });
        };
    }
}

这是输出:

Resolving Meta<Lazy<IFoo>>[]
    Component.Activator.LimitType:        Meta<Lazy<IFoo>>[]
    Component.Target.Activator.LimitType: Meta<Lazy<IFoo>>[]
    Result is:                            Meta<Lazy<IFoo>>[]
Resolving Meta<Lazy<IFoo>>
    Component.Activator.LimitType:        Meta<Lazy<IFoo>>
    Component.Target.Activator.LimitType: Foo
    Result is:                            Foo
Done

1 个答案:

答案 0 :(得分:0)

您想知道谁在解析ALogger

您的代码使用在基本类型准备时注入的自定义参数。使用此功能,您可以访问基本类型。

现在的问题是你要解决IEnumerable<IFoo>,但由于CollectionRegistrationSource的工作方式,你无法得到你想要的东西。

您可以尝试将解析上下文转换为IInstanceLookup并获得您想要的内容:

protected override void AttachToComponentRegistration(
    IComponentRegistry componentRegistry, IComponentRegistration registration)
{
    registration.Preparing += (sender, args) =>
    {
        Console.WriteLine("Preparing {0}", registration.Activator
                                                       .LimitType
                                                       .GetPrettyName());

        args.Parameters = args.Parameters.Union(new[]
        {
            new ResolvedParameter(
                predicate: (pi, c) => pi.ParameterType == typeof(ALogger), 
                valueAccessor: (pi, c) =>
                {
                    Parameter limitTypeParameter = null; 
                    IInstanceLookup lookup = c as IInstanceLookup; 
                    if(lookup != null)
                    {
                        String prettyName = lookup.ComponentRegistration
                                                  .Activator
                                                  .LimitType
                                                  .GetPrettyName();
                        limitTypeParameter = new NamedParameter("limitType", prettyName); 
                    }
                    else 
                    {
                        limitTypeParameter = new NamedParameter("limitType", null); 
                    }

                    return c.Resolve<ALogger>(limitTypeParameter); 
                })
        });
    };
}