UnityContainer和内部构造函数

Sha*_*dix 10 c# internalsvisibleto ioc-container unity-container

我有一个内部构造函数的类,想要从Unity(2.0)解析它.

public class MyClass {
    internal MyClass(IService service) {
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我在做

_container.Resolve<MyClass>();
Run Code Online (Sandbox Code Playgroud)

当我这样做时,我有一个例外

Exception is: InvalidOperationException - The type MyClass cannot be constructed. 
Run Code Online (Sandbox Code Playgroud)

IService已注册,唯一的问题是构造函数是内部的.我真的希望这个类是公开的,但是我希望它只能通过工厂(我实际上在调用它container.Resolve<MyClass>())中创建.

有没有办法让Unity看到内部构造函数?像InternalsVisibleTo或者什么?

Jon*_*Jon 9

我挖了一些关于如何为此目的扩展Unity的内容,并找到了一些有趣的信息.

首先,Unity似乎通过内部解析来选择使用哪个构造函数IConstructorSelectorPolicy.包含在Unity中的是public abstract class ConstructorSelectorPolicyBase<TInjectionConstructorMarkerAttribute>,包括这个gem:

/// <summary>
/// Choose the constructor to call for the given type.
/// </summary>
/// <param name="context">Current build context</param>
/// <param name="resolverPolicyDestination">The <see cref='IPolicyList'/> to add any
/// generated resolver objects into.</param>
/// <returns>The chosen constructor.</returns>
public SelectedConstructor SelectConstructor(IBuilderContext context, IPolicyList resolverPolicyDestination)
{
    Type typeToConstruct = context.BuildKey.Type;
    ConstructorInfo ctor = FindInjectionConstructor(typeToConstruct) ?? FindLongestConstructor(typeToConstruct);
    if (ctor != null)
    {
        return CreateSelectedConstructor(context, resolverPolicyDestination, ctor);
    }
    return null;
}
Run Code Online (Sandbox Code Playgroud)

FindInjectionConstructor和company是private static这个类中最终调用的方法Type.GetConstructors(没有参数的重载,只返回public构造函数).这告诉我,如果你可以安排Unity使用你自己的构造函数选择器策略,它可以选择任何构造函数,那你就是金色的.

很好的文档说明如何制作和使用自己的容器扩展,所以我想你很可能自己创建CustomConstructorSelectorPolicy包含相关部分DefaultUnityConstructorSelectorPolicy(从抽象基类派生而来,除非你注册别的东西),ConstructorSelectorPolicyBase(从这个直接导出可能不会很好,因为关键方法不是virtual,但你可以重用代码).

因此,我认为这是可行的,适度的麻烦,但从工程的角度来看,最终的结果将非常"纯粹".


Ste*_*ven 6

Unity只会查看公共构造函数,因此您需要将此构造函数设为public.

我真的希望这个课程公开,但我希望它只能通过工厂创建

在这种情况下,创建一个工厂:

public class MyClassFactory : IMyClassFactory
{
    private readonly IService service;

    public MyClassFactory(IService service)
    {
        this.service = service;
    }

    MyClass IMyClassFactory.CreateNew()
    {
        return new MyClass(this.service);
    }
}
Run Code Online (Sandbox Code Playgroud)

并注册:

_container.Register<IMyClassFactory, MyClassFactory>();
Run Code Online (Sandbox Code Playgroud)

并解决:

_container.Resolve<IMyClassFactory>().CreateNew();
Run Code Online (Sandbox Code Playgroud)

你也可以使用Unity InjectionFactory:

container.Register<MyClass>(new InjectionFactory(c => 
{   
    return new MyClass(c.Resolve<IService>());
})); 
Run Code Online (Sandbox Code Playgroud)

为此,保存此代码的程序集应该能够看到包含该代码的程序集的内部MyClass.换句话说,MyClass组件应标有InternalsVisibleTo.

还有以下几点:

public static class MyClassFactory
{
    public static MyClass CreateNew(IService service)
    {
        return new MyClass(service);
    }
}

container.Register<MyClass>(new InjectionFactory(c => 
{   
    return MyClassFactory.Create(c.Resolve<IService>());
})); 
Run Code Online (Sandbox Code Playgroud)

虽然您不必将构造函数公开,但这是混淆代码的好方法:-)