简体   繁体   English

如何将Unity与内部类一起使用?

[英]How can I use Unity with internal classes?

I have a Web API application and am using Unity for dependency injection. 我有一个Web API应用程序,并使用Unity进行依赖注入。 The application uses a library containing an Interface IDoStuff and a class that implements the interface: 该应用程序使用包含Interface IDoStuff的库和实现该接口的类:

internal interface IDoStuff
{
    void DoSomething();
}

internal class DoStuff : IDoStuff
{
    public void DoSomething()
    {
        // Do some stuff
    }
}

The library also has an public class that needs to do stuff: 该库还有一个需要做的事情的公共类:

public class NeedToDoStuff
{
    private IDoStuff doStuff;

    public NeedToDoStuff()
    {
        this.doStuff = new DoStuff();
    }

    internal NeedToDoStuff(IDoStuff doStuff)
    {
        this.doStuff = doStuff;
    }

    void PleaseDoStuff()
    {
        doStuff.DoSomething();
    }
}

I'd like to use Unity to create a NeedToDoStuff instance in my controller and to also be responsible for creating the DoStuff class internally, rather than the constructor calling new directly. 我想使用Unity在我的控制器中创建一个NeedToDoStuff实例,并负责在内部创建DoStuff类,而不是直接调用new的构造函数。 However, the only way I can see to do this is to make both the IDoStuff interface and DoStuff class public which seems wrong to me. 但是,我能看到的唯一方法是将IDoStuff接口和DoStuff类都公开,这对我来说似乎是错误的。 It seems wrong as these are implementation details and only relevant within the library itself. 这似乎是错误的,因为这些是实现细节,只与库本身相关。 I get that with inversion of control you're allowing the top level application to make choices about its underlying implementations via configuration of some sort but should this mean that there's no longer a need for internal etc? 我通过控制反转得到了你允许顶级应用程序通过某种配置对其底层实现做出选择,但是这是否意味着不再需要内部等?

Forget for a moment that you are using a container and let's say that you create those classes yourself in the startup path of your application. 忘记你正在使用容器,让我们说你自己在应用程序的启动路径创建这些类 How would you actually do this in C#? 你怎么在C#中实际做到这一点?

The answer is, you can't. 答案是,你做不到。 This will simply not compile in C#, because C# requires those types to be public. 这不会在C#中编译,因为C#要求这些类型是公共的。 So although those types might be an implementation detail to other components, they are not an implementation detail to the part of your application that wires them together. 因此,虽然这些类型可能是其他组件的实现细节,但它们并不是应用程序将它们连接在一起的实现细节。 Whether or not you use a DI library to help you is irrelevant; 你是否使用DI库来帮助你是无关紧要的; that library needs access to those libraries, because to the library, those classes are not implementation details. 该库需要访问这些库,因为对于库,这些类不是实现细节。

And do note that there are different ways of hiding those classes. 并注意隐藏这些类有不同的方法。 You can move the interfaces into their own assembly and let both the consuming library and the library that contains the implementations depend on that new 'contract' assembly. 您可以将接口移动到它们自己的程序集中,让消费库和包含这些实现的库都依赖于新的“契约”程序集。 When you don't let the consuming assembly depend on the implementation assembly, the implementation types are effectively hidden from the consuming assembly, even though those types are still public. 如果不让使用程序集依赖于实现程序集,则实现类型会从使用程序集中有效隐藏,即使这些类型仍然是公共的。

While I am personally against internal interfaces you can allow unity to use them by adding 虽然我个人反对内部接口,但您可以通过添加允许团结使用它们

[assembly: InternalsVisibleTo("Unity_ILEmit_InterfaceProxies")] 

to the AssemblyInfo.cs file of the project containing your interfaces. 到包含您的接口的项目的AssemblyInfo.cs文件。 I found this after attemping to add [assembly: InternalsVisibleTo("Microsoft.Practices.Unity")] which I have seen not work in other post and had no effect, but felt it was the right direction. 我在尝试添加[assembly:InternalsVisibleTo(“Microsoft.Practices.Unity”)]之后发现了这个,我看到它在其他帖子中没有用,并且没有效果,但觉得这是正确的方向。 The stacktrace I pulled from my code referenced the assembly above and allowed the code to work. 我从代码中提取的堆栈跟踪引用了上面的程序集并允许代码工作。

This would allow you to hide your Interfaces. 这将允许您隐藏您的接口。 The constructor is another story though. 构造函数是另一个故事。

I've posted my own answer as I believe it comes closest to answering my original question. 我发布了自己的答案,因为我认为它最接近于回答我原来的问题。 It may not be as clean a design choice as Steven's recommendations but love it or hate it, it does allow for the internal classes of a library to be used in conjunction with Unity. 它可能不像Steven的建议那样干净,但是喜欢或讨厌它,它确实允许库的内部类与Unity结合使用。

I needed to make three updates to the classes/interfaces: 我需要对类/接口进行三次更新:

  1. Make the interfaces public. 使接口公开。
  2. Make the constructors public. 使构造函数公开。
  3. Introduce a static class/method that performs unity registration within the library that is called from the main unity registration logic performed on application start up. 引入一个静态类/方法,在库中执行统一注册,从应用程序启动时执行的主统一注册逻辑调用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM