使用依赖注入返回用户定义的对象

时间:2015-03-30 13:59:14

标签: c# architecture dependency-injection ninject

我正在使用Ninject进行依赖注入,并且在传递基本类型时我已经很好地工作了,但是当我开始传递自定义对象类型时,我不确定构建应用程序的最佳方法。

这是一个简单的例子。我有4个项目:Main,Project A,Project B和Interfaces。主要参考ProjectA,ProjectB和Interfaces以及Project A和ProjectB参考接口。

在Interfaces中我定义了一个接口IClassA,它有一个返回int的方法。

public interface IClassA
{
    int ReturnFundamental();
}

在ProjectA中,我有ClassA,它实现了IClassA。

public class ClassA : IClassA
{
    public int ReturnFundamental()
    {
        return 1;
    }
}

ProjectB包含ClassB,它接受IClassA作为基于构造函数的依赖注入。它还提供了一种方法,允许我调用IClassA中定义的方法并在ClassA中实现。

public class ClassB
{
    private readonly IClassA classA;
    public ClassB(IClassA classA)
    {
        this.classA = classA;
    }
    public void GetObject()
    {
        Console.WriteLine(classA.ReturnFundamental());
    }
}

Main项目设置Ninject,将IClassA绑定到ClassA,实例化ClassB的实例并在ClassB上调用方法。

static void Main(string[] args)
{
    IKernel kernel = new StandardKernel();
    kernel.Bind<IClassA>().To<ClassA>();
    var classB = kernel.Get<ClassB>();
    classB.GetObject();
    Console.Read();
}

这一切都很好,ClassB可以调用ClassA中的方法并返回值。但是,如果我不想返回基本类型,而是想返回我定义的自定义对象,那么最好的方法是什么?

如果我没有弄错,那么IClassA,ClassA和ClassB都需要对这个对象的引用,并且在与ClassA或ClassB相同的项目中定义它会导致依赖注入被用来避免的耦合。

所以我能想到的唯一解决方案是:

  1. 声明Interfaces项目中的所有对象

  2. 创建另一个项目以放置用于在接口之间传递数据的所有对象。

  3. 创建一个新项目,其中包含类之间单个交互所需的所有对象,其中每个交互都有自己引用的项目,其中包含所需的所有对象。

  4. 我在第一个选项中看到的问题是,不清楚哪些对象被哪些类使用,我担心Interfaces项目会变得太大,在一个位置包含太多信息。

    第二个选项与第一个选项共享相同的问题,因为它不清楚哪些对象被哪些类使用,但至少它将接口与仅用于传递数据的对象分开。然而,它会在项目之间添加更多的引用(假设每个接口至少传递一个对象)每个接口,并且实现该接口或使用该接口的每个类都需要对新项目的引用。

    第三个选项至少可以清楚地说明哪些类交互需要哪些对象,因为它们都被组合在一起,但是这会导致很多项目被创建。

    我认为这是一个很好的解决方案,因为它必定是一个非常常见的问题,但我不确定大型项目的最佳实现。

1 个答案:

答案 0 :(得分:1)

无需创建界面项目。 通常做的是将实现(-details)声明为internal,将interface声明为public。例如。

public class PersonInfo
{
    string FirstName { get; set; }
    string Surname { get; set; }
    Address Address { get; set; }
}

public interface IPersonSearchService
{
    IEnumerable<PersonInfo> Search(string keyword);
}

internal class PersonSearchService : IPersonSearchService
{
    ....
}

现在添加一个NinjectModule:

public class PersonSearchServiceModule : NinjectModule 
{
    public override void Load()
    {
        this.Bind<IPersonSearchService>().To<PersonSearchService>();
    }
}

并在Composition Root(Application Project,Main Project,.. whatchamacallit)中加载模块,由kernel.Load<PersonSearchServiceModule>()显式加载Modulekernel.Load(IEnumerable<Assembly>)一个(或多个)程序集加载{{ 1}}重载。

使用Feature-Namespaces也是一个好主意。