【问题标题】:how to Resolve circular reference thorough IoC? [duplicate]如何通过 IoC 解决循环引用? [复制]
【发布时间】:2011-03-14 07:53:41
【问题描述】:

可能重复:
Can dependency injection prevent a circular dependency?

我正在开发一个框架,它将提供各种服务,如 dal、与共享点的集成、异常处理等。

我需要在 IoC 中做这件事,我对这种方法不熟悉。[我的做法似乎有循环参考]

所以在我看来我们会有三种类型的项目

  • 接口:最好是单独的项目
  • 实现接口的具体类项目(异常、dal、集成等服务项目)
  • bootstrapper\configurator(配置器):最好是一个单独的项目,如果它位于“接口”项目中,它将创建与具体类项目的循环引用,因为 IoC 需要接口和具体类的引用。

事情就是这样

  1. 具体类不应该有任何其他具体类的引用,因为这最终会创建循环引用。(如果有循环引用,它不会破坏 IoC 的全部目的,还是我错了? )。

  2. 其次,启动项目(单元测试、WCF 服务等)应该首先加载引导程序以获取所有类型的注册,所以我应该将引导程序项目添加到启动项目中,创建一个实例[单例] unity 容器注册所有类型。为了解决这些类型,我需要在每个其他服务项目中使用相同的实例。

所以我必须将引导程序项目添加到服务项目以进行类型解析。这种方法感觉不对,因为它会导致与我在第 1 点中提到的相同的问题(每个服务项目都将包含服务项目的引用)。

该怎么做呢?我尝试在注册时通过属性注入将 UnityContainer 作为属性添加到每个具体类中。我什至不确定这是否是正确的方法。我主要关心的是实现结果的最佳实践所以如果你能指导我完成这个我将非常感激......

提前谢谢你!

您更喜欢哪种方式来提高性能、配置、代码内类型注册或实例注册?

如果需要,我可以上传演示项目。我可以解释一件事。 Dal 使用异常管理器,异常管理器使用翻译器获取用户友好消息,翻译器使用 DAL 获取用户友好消息。这是我们有循环引用的一种情况。但是如果我们互相添加引用,可能会有很多。

[更新 - 包括示例代码] 我们还没有实现 IoC,所以你不会看到任何对它的引用 公共布尔更新() {
布尔结果 = 假;

        //Central DB
        IDataServiceManager oDataServiceMgr = null;
        DbTransaction oTrans = null;

        //Client DB
        IDataServiceManager oDataServiceMgrClient = null;
        DbTransaction oTransClient = null;

        try
        {

            oDataServiceMgr = new DataServiceManager(); //Connets to Centeral DB
            oTrans = oDataServiceMgr.BeginTransaction();

            if (this.UpdateUserData(oDataServiceMgr, oTrans))  //First Update in Center
            {
                oDataServiceMgrClient = new DataServiceManager(this.clientIDField); //Connects to client db
                oTransClient = oDataServiceMgrClient.BeginTransaction();
                if (this.UpdateUserData(oDataServiceMgrClient, oTransClient))
                    result = true;
            }

            if (result)
            {
                oTrans.Commit(); //Center DB
                oTransClient.Commit(); //Center DB
            }


        }
        catch (UserServiceException ex)
        {
            this._UserServiceException = new UserServiceException();
            SnapFlow.ExceptionHandling.ExceptionHandler.Wrap(this._UserServiceException, ex, true);
            throw this._UserServiceException;
        }

        finally 
        {
            if (!result && oTrans != null)
                oTrans.Rollback();

            if (!result && oTransClient != null)
                oTransClient.Rollback();

        }

        return result;
    }

【问题讨论】:

标签: c# .net inversion-of-control unity-container circular-reference


【解决方案1】:

与任何循环引用一样,您需要查看代码本身的实际架构。把 IoC/DI 放在一边,看看你的循环引用发生在哪里并重构。这些参考真的需要在那里吗?有没有更好的设计可以使用?

【讨论】:

    【解决方案2】:

    注意:我对 Unity 了解不多,但我与其他 ioc-containers 合作过

    如果我对您的理解正确,您想知道如何布局您的项目以避免循环引用。在我看来,您需要这些项目(dll)

    • Waqas.Base.dll 包含所有接口。不依赖统一或任何其他 Waqas.*.dll
    • 一个或多个包含服务实现的 dll,dal,...(即 Waqas.Service.Payment.dll)仅依赖于 Waqas.Base.dll,不依赖于统一
    • 一个知道 Waqas.Base.dll 和所有其他 Waqas.*.dll 的引导程序组件(理想情况下只有一种方法)。它的唯一职责是连接系统。这是唯一知道统一性的组件。
    • 您的主应用程序和集成测试使用引导程序。
    • 如果您有单元测试,您可以通过将服务、dal 等替换为模拟来手动连接测试。

    (更新)示例

    waqas.service.payment 需要访问 dal 而不引用引导程序或统一:

    改变旧版本

        public class PaymentService
        {
            public PaymentService();
    
            SavePayment( ...)
            {
                             IDAL dal = ioCContainer.resolve<IDAL>();
                             dal.Save(...);
            }
        }
    

    到新版本

        public class PaymentService
        {
            IDAL theDal;
            public PaymentService(IDAL dal) {theDal = dal;};
    
            SavePayment(...)
            {
                 theDal.Save(...);
            }
        }
    

    引导程序负责创建 Dal 和 PaymentService 并将它们相互连接。 IDal 在 Waqas.Base.dll 中定义。

    【讨论】:

    • 这些是我已有的项目(dll)。但是可以说我需要在 waqas.service.payment 中使用 dal,然后它需要支付项目添加引导程序引用来解析映射。例如public void savepayment() { IDAL dal = ioCContainer.resolve } 现在 iocContainer 应该是知道所有注册类型来解析 IDAL 的实例。如果没有所有服务项目中的引导程序项目引用,这是无法实现的
    • 我完全同意 k3b。总结一下:使用构造函数注入模式,而不是服务定位器模式。不要在单元测试中使用 Unity,仅(可选)在集成测试中使用。有循环引用通常是不正确设计的标志。 k3b++。
    • 谢谢,但还有一个问题。付款可以使用参数化构造函数(当它连接到客户数据库时)或默认构造函数(当它连接到主数据库时)创建 dal,这取决于调用 dal 的函数。 UpatePaymentToClient 可以使用客户端数据库,UpdatePayment 可以调用连接到主数据库的 dal。很抱歉打扰你:)
    • 因此您需要两个不同的 PaymentServe 实例,一个连接到 maindb,另一个使用不同的 dal 实例连接到不同的数据库
    • @Waqas:我再次同意 k3b:似乎该类有多种职责:您应该将它们分开。如果该服务连接到一个数据库,它就不可能有一个默认的构造函数,因为这意味着你没有使用依赖注入。依赖注入是要走的路。 DI 最佳实践是让每个服务只有一个公共构造函数,您可以在其中注入所有依赖项。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-15
    • 1970-01-01
    相关资源
    最近更新 更多