简体   繁体   English

如何解决循环引用?

[英]How to solve circular reference?

How do you solve circular reference problems like Class A has class B as one of its properties, while Class B has Class A as one of its properties?您如何解决循环引用问题,例如 A 类将 B 类作为其属性之一,而 B 类将 A 类作为其属性之一?

How to do architect for those kind of problems?遇到这些问题怎么做架构师?

If you take an example of NHibernate, there will be a parent-child relationship between objects.如果以NHibernate为例,对象之间就会存在父子关系。

How is it able to handle those parent child scenarios?它如何处理这些父子场景?

In most cases when I've had to have two things reference each other, I've created an interface to remove the circular reference.在大多数情况下,当我不得不让两个东西相互引用时,我创建了一个接口来删除循环引用。 For example:例如:

BEFORE

public class Foo
{
    Bar myBar;
}

public class Bar
{
    Foo myFoo;
}

Dependency graph:依赖图:

Foo     Bar
 ^       ^
 |       |
Bar     Foo

Foo depends on Bar, but Bar also depends on Foo. Foo 依赖于 Bar,但 Bar 也依赖于 Foo。 If they are in separate assemblies, you will have problems building, particularly if you do a clean rebuild.如果它们在单独的程序集中,您将在构建时遇到问题,尤其是在您进行干净的重建时。

AFTER

public interface IBar
{
}

public class Foo
{
    IBar myBar;
}

public class Bar : IBar
{
    Foo myFoo;
}

Dependency graph:依赖图:

Foo, IBar     IBar
    ^          ^
    |          |
   Bar        Foo

Both Foo and Bar depend on IBar. Foo 和 Bar 都依赖于 IBar。 There is no circular dependency, and if IBar is placed in its own assembly, Foo and Bar being in separate assemblies will no longer be an issue.没有循环依赖,如果 IBar 放在它自己的程序集中,Foo 和 Bar 在单独的程序集中将不再是一个问题。

I would tell your friend he needs to rethink his design.我会告诉你的朋友他需要重新考虑他的设计。 Circular references like you describe are often a code smell of a design flaw.像您描述的循环引用通常是设计缺陷的代码味道。

Unlike C++ (for instance), C# does not need forward declarations to resolve circular references.与 C++(例如)不同,C# 不需要前向声明来解析循环引用。 Hence:因此:

public class A
{
    public B B { get;set; }
}

public class B
{
    public A A { get;set; }
}

However, this is often an indicator of questionable design decisions.然而,这通常是有问题的设计决策的一个指标。

In most every case the best solution is to change your design and avoid a circular dependency.在大多数情况下,最好的解决方案是更改您的设计并避免循环依赖。 For instance you may do one of the following:例如,您可以执行以下操作之一:

  1. Move the common referenced code to a utility project in your solution and have the other projects reference the Utility project将公共引用代码移动到解决方案中的实用程序项目,并让其他项目引用实用程序项目
  2. Use an interface as explained by "Ed Bayiates" in his answer.使用“Ed Bayiates”在他的回答中解释的界面。
  3. If its a small amount of simple/common code then rewrite it for one of the classes so you don't need to reference it in a circular dependency.如果它是少量的简单/通用代码,则为其中一个类重写它,这样您就不需要在循环依赖中引用它。 (my least favorite) (我最不喜欢的)

However, if you are working in a solution with many projects and you don't have the ability to make one of the changes above because you don't own the code, its to difficult to implement, or not worth the time to fix, then You can use this method:但是,如果您正在处理包含许多项目的解决方案,并且由于您不拥有代码而无法进行上述更改之一,则代码难以实施,或者不值得花时间修复,那么你可以使用这个方法:

Right-click on the project references and select "Add Reference...".右键单击项目引用并选择“添加引用...”。 Then in the dialog window that appears switch to the "Browse" tab and the "Browse" button.然后在出现的对话窗口中切换到“浏览”选项卡和“浏览”按钮。 From there you can go find the DLL and select it.从那里您可以找到 DLL 并选择它。 This is a work around at best and can cause build problems especially if both DLLs are being updated frequently, and/or have many dependencies.这充其量是一种解决方法,可能会导致构建问题,尤其是在两个 DLL 都经常更新和/或具有许多依赖项的情况下。 I do not recommend this method but it works in a pinch.我不推荐这种方法,但它在紧要关头工作。

Fissh

接口是一个好主意,但是如果您正在寻找比重做这么多东西的架构更快的解决方案,请尝试构建一个包含所有数据结构的 dll 类库,您的主项目包含需要该数据的 UI,然后是您想要的任何其他 dll添加也可以访问该数据结构 dll,因此它们拥有运行所需的所有信息,但仍然可以分开 - 这称为三力设计模式 -

Circular reference occurs when two or more interdependent resources cause lock condition.当两个或多个相互依赖的资源导致锁定条件时,就会发生循环引用。 This makes the resource unusable.这使得资源无法使用。

To handle the problem of circular references in C#, you should use garbage collection.要处理 C# 中的循环引用问题,您应该使用垃圾收集。 It detects and collects circular references.它检测并收集循环引用。 The garbage collector begins with local and static and it marks each object that can be reached through their children.垃圾收集器从本地和静态开始,它标记每个可以通过其子项访问的对象。

Through this, you can handle the issues with circular references.通过这个,你可以处理循环引用的问题。

Let's say the following classes is in circular reference.假设以下类处于循环引用中。 Here both of them depends on each other −在这里,它们彼此依赖 -

public class A
        {
            B Two;
        }
public class B
        {
            A one;
        }

To solve the issue, create an interface −为了解决这个问题,创建一个接口 -

public interface myInterface {
}

public class A {
   myInterface Two;
}

public class B: myInterface {
   A one;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM