如何通过IoC解决循环引用?

时间:2011-03-14 07:53:41

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

  

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

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

我需要在IoC中这样做,我对这种方法不熟悉。[似乎有关于我如何做的循环参考]

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

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

现在就是这件事

  1. 具体类不应该引用任何其他具体类,因为这最终会创建循环引用。(如果有循环引用,它不会杀死IoC的整个目的,或者我错了吗? )。

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

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

    如何去做?我已经尝试在注册时通过属性注入将UnityContainer添加为每个具体类中的属性。我甚至不确定这是否正确。我主要关心的是实现结果的最佳实践所以,如果你可以指导我完成这一点,我将非常感谢......

    提前谢谢!

    您更喜欢哪种方式的性能,配置,代码内类型注册或实例注册?

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

    [更新 - 包含示例代码] 我们还没有实现IoC,所以你不会看到它的任何引用 public bool更新()         {
                bool result = false;

            //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;
        }
    

2 个答案:

答案 0 :(得分:4)

与任何循环引用一样,您需要查看代码本身的实际体系结构。将IoC / DI放在一边,看一下循环引用的发生位置和重构。真的需要这些参考吗?您可以使用更好的设计吗?

答案 1 :(得分:1)

注意:我不太了解Unity但我使用其他ioc容器

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

  • 包含所有接口的Waqas.Base.dll。没有依赖统一或任何其他Waqas。*。dll
  • 一个或多个包含服务实现的dll,dal,...(即Waqas.Service.Payment.dll)仅依赖于Waqas.Base.dll而不依赖于统一
  • 一个知道Waqas.Base.dll和所有其他Waqas。*。dll的Bootstrapper组件(理想情况下只有一个方法)。它唯一的责任是连接系统。这是唯一知道团结的组成部分。
  • 您的主要应用程序和集成测试使用引导程序。
  • 如果您进行了单元测试,则可以通过使用模拟替换seriveces,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中定义。