Как решить круговую ссылку? - PullRequest
22 голосов
/ 03 августа 2011

Как вы решаете задачи с круговыми ссылками, например, у класса A есть класс B в качестве одного из его свойств, а у класса B - класс A в качестве одного из его свойств?

Как создать архитектуру для таких задач?

Если вы возьмете пример NHibernate, между объектами будут отношения родитель-потомок.

Как он может обрабатывать эти родительские дочерние сценарии?

Ответы [ 6 ]

28 голосов
/ 03 августа 2011

В большинстве случаев, когда мне нужно, чтобы две вещи ссылались друг на друга, я создал интерфейс для удаления циклической ссылки. Например:

до

public class Foo
{
    Bar myBar;
}

public class Bar
{
    Foo myFoo;
}

График зависимостей:

Foo     Bar
 ^       ^
 |       |
Bar     Foo

Foo зависит от Bar, но Bar также зависит от Foo. Если они находятся в отдельных сборках, у вас будут проблемы со сборкой, особенно если вы делаете чистую перестройку.

ПОСЛЕ

public interface IBar
{
}

public class Foo
{
    IBar myBar;
}

public class Bar : IBar
{
    Foo myFoo;
}

График зависимостей:

Foo, IBar     IBar
    ^          ^
    |          |
   Bar        Foo

Foo и Bar зависят от IBar. Круговой зависимости нет, и если IBar размещен в его собственной сборке, Foo и Bar, находящиеся в отдельных сборках, больше не будут проблемой.

6 голосов
/ 03 августа 2011

Я бы сказал вашему другу, что ему нужно переосмыслить свой дизайн. Циркулярные ссылки, которые вы описываете, часто являются кодовым запахом недостатка дизайна.

5 голосов
/ 03 августа 2011

В отличие от C ++ (например), C # не нуждается в предварительных объявлениях для разрешения циклических ссылок. Следовательно:

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

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

Однако это часто показатель сомнительных проектных решений.

1 голос
/ 17 февраля 2017

В большинстве случаев лучшим решением является изменение вашего дизайна и избежание круговой зависимости.Например, вы можете выполнить одно из следующих действий:

  1. Переместить общий ссылочный код в служебный проект в вашем решении, а другие проекты ссылаются на служебный проект
  2. Использовать интерфейс какобъяснил «Эд Байятс» в своем ответе.
  3. Если это небольшой объем простого / общего кода, перепишите его для одного из классов, чтобы вам не нужно было ссылаться на него в циклической зависимости.(мой наименее любимый)

Однако, если вы работаете в решении со многими проектами и у вас нет возможности внести одно из указанных выше изменений, потому что у вас нет кода,Его сложно реализовать или не стоит затрачивать время на исправление, затем вы можете использовать этот метод:

Щелкните правой кнопкой мыши на ссылках проекта и выберите «Добавить ссылку ...».Затем в появившемся диалоговом окне перейдите на вкладку «Обзор» и кнопку «Обзор».Оттуда вы можете найти DLL и выбрать ее.В лучшем случае это обходной путь, который может вызвать проблемы со сборкой, особенно если обе DLL часто обновляются и / или имеют много зависимостей.Я не рекомендую этот метод, но он работает в крайнем случае.

Fissh

0 голосов
/ 17 июня 2019

Циркулярная ссылка возникает, когда два или более взаимозависимых ресурса вызывают состояние блокировки. Это делает ресурс непригодным для использования.

Чтобы решить проблему циклических ссылок в C #, вы должны использовать сборщик мусора. Он обнаруживает и собирает циркулярные ссылки. Сборщик мусора начинается с локального и статического и помечает каждый объект, который может быть достигнут через их потомков.

Благодаря этому вы можете решать проблемы с помощью циклических ссылок.

Допустим, следующие классы находятся в циклической ссылке. Здесь оба они зависят друг от друга -

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

Для решения проблемы создайте интерфейс -

public interface myInterface {
}

public class A {
   myInterface Two;
}

public class B: myInterface {
   A one;
}
0 голосов
/ 26 октября 2017
Однако,

интерфейсы - хорошая идея, если вы ищете более быстрое решение, чем переделка архитектуры многих вещей, попробуйте создать одну библиотеку классов dll, которая содержит все ваши структуры данных, ваш основной проект содержит ваш пользовательский интерфейс, которому нужны эти данные, а затем любые другиеDLL-файлы, которые вы хотите добавить, могут также обращаться к этим структурам данных DLL, чтобы они имели всю информацию, необходимую для запуска, но все же могут быть отдельными - это называется шаблоном проектирования tri force -

...