【问题标题】:How to resolve public class with internal constructor on AutoFac如何在 AutoFac 上使用内部构造函数解析公共类
【发布时间】:2018-10-13 12:44:19
【问题描述】:

我要在单元测试中实例化这个类:

public class Customer
{
    internal Customer(Guid id) {
        // initialize property
    }
}

如果我使用 new Customer() 从另一个 (unittests) 程序集实例化测试类,因为我添加了 [assembly: InternalsVisibleTo("MyProject.Tests")]

var sut = new Customer(Guid.NewGuid()); // works

但是当我在另一个(unittest)程序集中设置一个 autofac 容器时

var builder = new ContainerBuilder();
builder.RegisterType<Customer>().AsSelf();
var container = builder.Build();

我无法用 autofac 解决。

var theParam = new NamedParameter("id", Guid.NewGuid());
_sut = container.Resolve<Customer>(theParam); // throws exception

我最好的猜测是内部构造函数不可用。但是在另一个旁边添加[assembly: InternalsVisibleTo("Autofac")] 并没有帮助。

Autofac 抛出的异常是

Autofac.Core.DependencyResolutionException: 
An error occurred during the activation of a particular registration. See the inner exception for details. 
Registration: Activator = Customer (ReflectionActivator), 
Services = [MyProject.Customer], 
Lifetime = Autofac.Core.Lifetime.CurrentScopeLifetime, 
Sharing = None, 
Ownership = OwnedByLifetimeScope 
---> No accessible constructors were found for the type 'MyProject.Customer'. 

Autofac 不能处理 internal 构造函数吗?

【问题讨论】:

    标签: autofac


    【解决方案1】:

    Autofac 无法定位非公共构造函数,因为它使用DefaultConstructorFinder 类,默认情况下只搜索公共构造函数。

    您必须像这样创建 IConstructorFinder 接口的自定义实现:

    public class AllConstructorFinder : IConstructorFinder 
    { 
        private static readonly ConcurrentDictionary<Type, ConstructorInfo[]> Cache =
            new ConcurrentDictionary<Type, ConstructorInfo[]>();
    
    
        public ConstructorInfo[] FindConstructors(Type targetType)
        {
            var result = Cache.GetOrAdd(targetType,
                t => t.GetTypeInfo().DeclaredConstructors.Where(c => !c.IsStatic).ToArray());
    
            return result.Length > 0 ? result : throw new NoConstructorsFoundException(targetType);
        } 
    } 
    

    那么你必须在类型注册上使用FindConstructorsWith扩展方法:

    builder.RegisterType<Customer>()
       .FindConstructorsWith(new AllConstructorFinder())
       .AsSelf();
    

    InternalsVisibleToAttribute 在这种情况下无能为力,因为它只影响编译时间。

    【讨论】:

    • 那是用非常体面的英语给出的非常明确的答案。没必要道歉! :-)
    • 我不得不承认 Autofac 需要这样的东西来处理内部类,这很糟糕。这表明使用internal关键字并不是很流行的方法。
    • @serafim-prozorov 这是一个很好的解决方案,我认为,只需要为AllConstructorFinder添加一个附加条件:...DeclaredConstructors.Where (c =&gt; !c.IsStatic)... 否则假设所有静态构造函数都会导致异常比如:“不能在类型上长度为 0 的多个构造函数之间进行选择”。
    猜你喜欢
    • 1970-01-01
    • 2011-04-16
    • 2016-07-31
    • 2017-05-11
    • 1970-01-01
    • 1970-01-01
    • 2019-02-28
    • 1970-01-01
    • 2016-08-15
    相关资源
    最近更新 更多