C# UnityContainer和内部构造函数

C# UnityContainer和内部构造函数,c#,unity-container,ioc-container,internalsvisibleto,C#,Unity Container,Ioc Container,Internalsvisibleto,我有一个具有内部构造函数的类,希望从Unity(2.0)解析它 那我要做什么 _container.Resolve<MyClass>(); IService已注册,唯一的问题是构造函数是内部的。 我确实希望这个类是公共的,但我希望它只能通过工厂创建(在工厂中我实际上调用了container.Resolve()) 有没有办法让Unity看到内部构造函数?例如InternalsVisibleTo或其他什么?可能有一些变通方法/黑客可以让您使用Unity 9实现这一点(我不知道是否有),

我有一个具有内部构造函数的类,希望从Unity(2.0)解析它

那我要做什么

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


有没有办法让Unity看到内部构造函数?例如InternalsVisibleTo或其他什么?

可能有一些变通方法/黑客可以让您使用Unity 9实现这一点(我不知道是否有),但一般来说,如果您希望一个类由Unity(或任何IOC容器)管理,则需要使用公共构造函数将其公开


一种选择可能是创建一个抽象工厂来创建具有公共构造函数的类,并将该类的构造函数保持在内部。缺点是你的工厂将由Unity管理,但你的类本身不会。Unity只会查看公共构造函数,所以你需要将这个构造函数公开

我真的希望这门课是公开的, 但我希望它只能通过 工厂

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

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>();
为此,保存此代码的程序集应该能够看到保存
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>());
})); 
公共静态类MyClassFactory
{
公共静态MyClass CreateNew(iSeries服务)
{
返回新的MyClass(服务);
}
}
容器。注册(新注入工厂(c=>
{   
返回MyClassFactory.Create(c.Resolve());
})); 

尽管不必公开构造函数,但这是混淆代码的一种很好的方法:-)

我深入研究了如何为此扩展Unity,并发现了一些有趣的信息

首先,Unity似乎通过内部解析
IConstructorSelectorPolicy
来选择要使用的构造函数。Unity中包括
公共抽象类构造函数SelectorPolicyBase
,其中包括以下内容:

/// <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;
}
//
///选择要为给定类型调用的构造函数。
/// 
///当前构建上下文
///要添加任何
///将生成的冲突解决程序对象转换为。
///选择的构造函数。
public SelectedConstructor SelectConstructor(IBuilderContext上下文,IPolicyList resolverPolicyDestination)
{
类型typeToConstruct=context.BuildKey.Type;
ConstructorInfo-ctor=FindInjectionConstructor(typeToConstruct)??FindLongTestConstructor(typeToConstruct);
如果(ctor!=null)
{
返回CreateSelectedConstructor(上下文、resolverPolicyDestination、构造函数);
}
返回null;
}
FindInjectionConstructor
和company是此类中的
私有静态
方法,它们最终调用
Type.GetConstructors
(不带参数的重载,只返回
公共
构造函数)。这告诉我,如果您可以安排Unity使用您自己的构造函数选择器策略,该策略可以选择任何构造函数,那么您就是golden

这是关于如何制作和使用您自己的容器扩展的,因此我认为很有可能制作您自己的
CustomConstructorSelectorPolicy
,其中包括的相关部分(它派生自抽象基类,是默认的,除非您注册其他内容)和(直接从中派生可能不会很好地工作,因为关键方法不是
虚拟的
,但您可以重用代码)


因此,我想说,这是可行的,只需要适度的麻烦,但从工程的角度来看,最终结果将是相当“纯粹的”。

只需将类内部化,并将构造函数公开

  • 接口公共
  • 类内部
  • 类public的构造函数

  • “它需要使用公共构造函数公开。”-这是错误的,Unity可以完美地使用具有公共构造函数的内部类。当我想使用IoC管理我的内部依赖项时就是这种情况。我所做的是一个抽象工厂。我想在其中创建MyClass的实例。我可以创建新的MyClass(_container.Resolve()),但不想手动执行。谢谢,这几乎正是我正在做的:)我只是不喜欢每次我的类依赖项改变时都改变工厂。那么,寻找一种通过Unity直接实现的方法,你为什么不想公开呢?您正在创建可重用库吗?以下是使用自定义
    IConstructorSelectorPolicy
    _container.Resolve<IMyClassFactory>().CreateNew();
    
    container.Register<MyClass>(new InjectionFactory(c => 
    {   
        return new MyClass(c.Resolve<IService>());
    })); 
    
    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>());
    })); 
    
    /// <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;
    }