Поддержание согласованности графов объектов - PullRequest
2 голосов
/ 01 февраля 2009

У меня есть ситуация, когда объект A имеет ссылку на объект B. B также имеет ссылку обратно на A. Для простоты, скажем, A и B одного типа. Как сделать так, чтобы при обновлении ссылки на A это обновление также отражалось на B (и наоборот)?

Пример интерфейса такого типа:

interface IGraphNode
{
    IGraphNode From { get; set; }
    IGraphNode To { get; set; } 
}

После выполнения кода ниже, я ожидаю, что B.From вернет A.

IGraphNode A = new GraphNode();
IGraphNode B = new GraphNode();
A.To = B;

Ответы [ 4 ]

1 голос
/ 01 февраля 2009
IGraphNode From
{ 
    get { return from; }
    set 
    {
        from = value;
        if (value.To != this) {
            value.To = this;
        }
    }
}

IGraphNode To
{
    get { return to; }
    set
    {
        to = value;
        if (value.From != this) {
            value.From = this;
        }
    }
}

Возможно, вы захотите расширить его проверкой, если (значение == это) ...

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

0 голосов
/ 03 февраля 2009

Хотя принятый ответ умный, я не фанат этого. В частности, часть об изменении «значения» внутри свойства. Методы / свойства не должны иметь скрытых побочных эффектов . Подобные практики обычно приводят к неожиданному поведению, которое трудно отследить. Не естественно ожидать, что вызов свойства в A изменил бы мой объект B. Я бы знал это, только если бы я подробно изучил код? Много раз исходный код даже не доступен.

Лучшим решением было бы создать явный метод, который сделал бы операцию и любые побочные эффекты более очевидными, такие как:

void ConnectNodes(IGraphNode a, IGraphNode b)
{
    a.to = b;
    b.from = a;
}

или

void ConnectNodes(IGraphNode b)
{
    this.to = b;
    b.from = this;
}
0 голосов
/ 01 февраля 2009

Вам понадобится уведомить B о ссылке, возможно, просто установив свойство B.From.

Однако вам нужно подумать о том, что, если более чем один объект получает ссылку на B:

IGraphNode A = new GraphNode();
IGraphNode B = new GraphNode();
IGraphNode C = new GraphNode();

A.To = B;
C.To = B;

// what should B.From return?

Кроме того, подумайте о том, что произойдет, если один из объектов, на которые есть ссылки, не имеет других ссылок? Например:

IGraphNode A = new GraphNode();
IGraphNode B = new GraphNode();

A.To = B;
A = null;  // should the reference from B keep the object 
           // that A used to reference alive?

Объект WeakReference вместо прямой ссылки может помочь в решении этой конкретной проблемы.

0 голосов
/ 01 февраля 2009

Вы должны явно указать:

A.To = B;
B.From = A;

Насколько это возможно, это так. Большинство объектно-ориентированных языков прозрачно имеют дело с циклическими ссылками, такими как эти.

Если вы хотите сделать эту двунаправленную ссылку автоматической, вы всегда можете расширить свой интерфейс IGraphNode и создать абстрактный базовый класс, содержащий некоторый код в ваших свойствах From и To, который устанавливает значение другого при изменении. Все GraphNodes, которые требуют этой автоматической функциональности, должны расширять базовый абстрактный класс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...