我正在解决一个 DI 问题,我认为我了解其原因,但我需要一些建议来解决。
我构建了一个与 Sql 对话的独立程序集(将此程序集称为 a),以及另一个包含业务逻辑的程序集(将此程序集称为 b)。我在 b 程序集中为 db 类创建了一个接口。由于该接口不是数据库程序集的一部分,因此我不需要对数据库项目的任何引用,并且如果我想在运行时运行单元测试而不是程序集,我可以加载对数据库程序集或存根的引用需要了解对方。
我可以在业务逻辑库中编写代码进行编译,如下所示:(假设 a 和 b 是各自程序集中的命名空间)
a.IDatabaseClass db_class = (a.IDatabase)new b.Database();
然而,当我尝试运行它时,我收到无效的强制转换异常。我认为它可以编译,因为接口与类完美匹配,但在运行时失败,因为对象签名在数据库类的继承链中看不到 IDatabase。
在 C++ 中,您可以随心所欲地进行任何类型的转换,但 C# 对于对象指针的转换要严格一些。即使该类具有所有正确的函数签名,它也会因为对象不匹配而崩溃。
现在我可以将数据库对象接口与数据库对象一起放入程序集中,但随后业务逻辑需要对数据库程序集的引用。另外,这只会在以后造成复杂性,因为如果我在单元测试中编写存根数据库对象,我需要对数据库程序集的引用,以用于我将在测试存根对象中使用的接口。这似乎并没有通过这样做来解开耦合......
我可以将所有接口放在第三个程序集中,该程序集是数据库程序集、业务逻辑和单元测试的父程序集。这就是解决循环依赖问题的方法。然而,这将数据库程序集与父程序集联系起来,并使其与其他项目一起使用时的模块化程度大大降低。
我愿意接受有关如何设置每个程序集的建议,以便它们独立运行并可用于 DI。我想我可以将测试存根对象保留在与真实代码相同的程序集中,但这看起来很奇怪。
解决方案
下面的回复之一评论说我拍摄的内容基本上是界面的鸭子类型。 C# 当前不支持鸭子类型,但我认为这可能是可能的,因为接口实现的行为方式类似于您可能称之为的部分类指针(或者更准确地说,函数指针的集合)。我的实验告诉我情况并非如此,这就是原因。
因此,在 Redmond 将“更多野鸭”放入 C# 之前,看起来我们无法达到完全解耦程序集的最终优雅水平。