我正在研究DI问题,我认为我理解其原因,但我需要一些建议来解决。
我构建了一个独立的程序集,它与Sql(称为程序集a)和另一个包含业务逻辑的程序集(称为程序集b)进行对话。我在b程序集中为db类创建了一个接口。由于接口不是db程序集的一部分,因此我不需要对db项目的任何引用,如果我想在运行时运行单元测试而不是程序集,我可以加载对db程序集或存根的引用需要知道另一个。
我可以在业务逻辑库中编写代码,这些代码看起来像这样:(假装a和b是各自程序集中的名称空间)
a.IDatabaseClass db_class = (a.IDatabase)new b.Database();
但是当我尝试运行它时,我得到一个无效的强制转换异常。我认为它编译是因为接口完全匹配类,但在运行时失败,因为对象签名在Database类的继承链中看不到IDatabase。
在c ++中,你可以随心所欲地投射任何东西,但c#对于投射对象指针有点严格。即使该类具有所有正确的函数签名,它也会因为对象不匹配而爆炸。
现在我可以将db对象接口放在具有db对象的程序集中,但是业务逻辑需要对db程序集的引用。此外,这只会产生复杂性,因为如果我在单元测试中编写存根db对象,我需要对我将在测试存根对象中使用的接口的db程序集的引用。这似乎并没有通过这样做解开耦合......
我可以将所有接口放在第三个程序集中,该程序集是db程序集,业务逻辑和单元测试的父级。这就是解决循环依赖问题的方法。但是,这会将db程序集绑定到父程序集,并使其与其他项目一起使用的模块化程度要低得多。
我愿意接受有关如何设置每个组件以便它们独立运行并可用于DI的建议。我想我可以将测试存根对象保存在与真实代码相同的程序集中,但这看起来很奇怪。
解决方案:下面的回复中的一个回复说明我拍摄的内容基本上是接口的鸭子类型。 C#目前不支持duck typing,但我认为这可能是可能的,因为接口实现的行为与你可能称之为部分类指针的方式类似(或者更准确地说,是函数指针的集合)。我的实验反过来告诉我,这就是原因。
所以,直到Redmond将“更多野鸭”放入c#,看起来我们无法完全达到最终优雅的解耦组件。
答案 0 :(得分:5)
创建包含常用接口的参考库。这样,您就可以获得与所有实现无关的逻辑的公共源。
我没有经验使自己有信心将其作为一个明确的陈述,但我强烈怀疑,当您谈论引用特定接口的个别类型及其行为时,耦合主要是一个问题。大会没有相同的特异性,可以解决问题。
让我修改和扩展。一个组件必须引用另一个组件,或者两者都必须引用一个公共组件。 C#没有鸭子接口,如果这是一件事。
现在我认为最佳做法是将业务逻辑与外部接口隔离开来,因此如果您要做任何事情,您应该将业务逻辑与数据库实现隔离开来。所以DB / Application程序集引用了业务逻辑,但不是相反。
答案 1 :(得分:3)
让客户端库(double myValue = 1.5;
Session.Query<Foo>().Where(x => x.IntProp < myValue*x.AnotherIntProp).ToList();
)定义接口,并从服务器库(b
)引用该库。
从Dependency Inversion Principle开始,“客户端[...]拥有抽象接口”(APPP,第11章),因此没有理由将接口放在第三个库中。< / p>