我有一个内部构造函数的类,想要从Unity(2.0)解析它。
public class MyClass {
internal MyClass(IService service) {
}
}
然后我正在做
_container.Resolve<MyClass>();
当我这样做时,我有一个例外
Exception is: InvalidOperationException - The type MyClass cannot be constructed.
IService已注册,唯一的问题是构造函数是内部的。
我真的希望这个类是公开的,但是我希望它只能通过工厂(我实际上正在调用container.Resolve<MyClass>()
)来创建。
有没有办法让Unity看到内部构造函数?像InternalsVisibleTo或者什么?
答案 0 :(得分:8)
我挖掘了一下如何为此目的扩展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;
}
FindInjectionConstructor
和公司是此类中的private static
方法,最终最终调用Type.GetConstructors
(没有参数的重载,只返回public
构造函数)。这告诉我,如果你可以安排Unity使用你自己的构造函数选择器策略,它可以选择任何构造函数,那你就是金。
有good documentation关于如何制作和使用自己的容器扩展,所以我想我们很有可能制作自己的CustomConstructorSelectorPolicy
,其中包含DefaultUnityConstructorSelectorPolicy
的相关部分(派生自从抽象基类开始,除非你注册其他内容,否则是默认值)和ConstructorSelectorPolicyBase
(直接从中导出可能不会很好,因为关键方法不是virtual
,但你可以重用代码)。
因此,我说这是可行的,有一定的麻烦,但从工程的角度来看,最终的结果将是非常“纯粹的”。
答案 1 :(得分: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);
}
}
并注册:
_container.Register<IMyClassFactory, MyClassFactory>();
并解决:
_container.Resolve<IMyClassFactory>().CreateNew();
您也可以使用Unity的InjectionFactory
:
container.Register<MyClass>(new InjectionFactory(c =>
{
return new MyClass(c.Resolve<IService>());
}));
为此,保存此代码的程序集应该能够看到包含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>());
}));
虽然您不必公开构造函数,但这是混淆代码的好方法: - )
答案 2 :(得分:2)
只需使类内部和构造函数公开...
答案 3 :(得分:0)
有可能有一些解决方法/黑客可以让你用Unity 9I做这个,不知道是否有),但一般来说如果你想让一个类由Unity(或任何IOC容器)管理,它需要与公共建设者一起公开。
一个选项可能是创建一个抽象工厂,创建具有公共构造函数的类,并将类的构造函数保持在内部。缺点是你的工厂将由Unity管理,但你的班级本身不会。