C #: есть ли способ легко найти / обновить все ссылки на объект? - PullRequest
6 голосов
/ 28 февраля 2010

Я читал «Эксперт C # 2008 Business Objects» Рокфорда Лхотки, где есть такая вещь, как портал данных, который хорошо абстрагирует, откуда поступают данные. При использовании DataPortal.Update (this), который, как вы можете догадаться, сохраняется «this» в базе данных, объект возвращается - постоянное «this» с любыми изменениями, внесенными в него БД, например. отметка времени.

Лхотка часто и очень небрежно писал, что вы должны обязательно обновить все ссылки на старый объект на новый возвращаемый объект. Имеет смысл, но есть ли простой способ найти все ссылки на старый объект и изменить их? Очевидно, что GC отслеживает ссылки, возможно ли использовать это?

Приветствия

Ответы [ 4 ]

5 голосов
/ 28 февраля 2010

Для этого есть API профилирования , но ничего для общего потребления. Одно из возможных решений, которое я использовал сам, состоит в том, чтобы реализовать в базовом классе механизм отслеживания, в котором каждый экземпляр объекта добавляет к себе статическую ссылку WeakReference.

Я условно скомпилирован для сборок DEBUG, но, вероятно, не стоит полагаться на это в сборке релиза.

// simplified example
// do not use. performance would suck
abstract class MyCommonBaseClass {

    static readonly List<WeakReference> instances = new List<WeakReference>();

    protected MyCommonBaseClass() {
        lock (instances) {
            RemoveDeadOnes();
            instances.Add(new WeakReference(this));
        }
    }

}
4 голосов
/ 28 февраля 2010

GC фактически не отслеживает ссылки на объекты. Вместо этого он вычисляет, какие объекты достижимы, начиная с глобальных и стековых объектов во время выполнения, и выполняя некоторый вариант алгоритма «заливки».

Специально для вашей проблемы, почему бы просто не иметь прокси, содержащую ссылку на «реальный» объект? Таким образом, вам нужно обновить только в одном месте.

0 голосов
/ 28 февраля 2010

Если вы передаете ссылки на объекты вокруг, и эти ссылки на объекты остаются неизменными, то любые изменения, внесенные в объект в слое постоянства, будут немедленно видны любым другим потребителям объекта. Однако, если ваш объект пересекает служебную границу, тогда сборки на каждой стороне объекта будут просматривать разные объекты, которые являются просто копиями. Кроме того, если вы сделали клоны объекта или создали анонимные типы, которые включают свойства исходного объекта, их будет сложно отследить - и, конечно, для GC это новые объекты, которые не имеют привязки к объекту. оригинальный объект.

Если у вас есть какой-то ключ или идентификатор в объекте, это становится проще. Ключ не обязательно должен быть идентификатором базы данных, это может быть GUID, который обновляется при создании экземпляра объекта и не изменяется в течение всего жизненного цикла объекта (т. Е. Это свойство имеет getter, но не setter) - поскольку это свойство сохраняется в границах службы, поэтому ваш объект все равно будет идентифицируемым. Затем вы можете использовать LINQ или даже старомодные циклы (icky!) Для перебора любой коллекции, которая может содержать копию обновленного объекта, и, если она найдена, вы можете объединить изменения обратно.

Сказав это, я не думаю, что у вас слишком много копий. Если вы делаете это, то места, где находятся эти копии, должны быть очень локализованы. Гарантия того, что ваш объект реализует INotifyPropertyChanged, также поможет распространять уведомления об изменениях, если вы удерживаете список в одном месте, которое затем прямо или косвенно связано в нескольких других местах.

0 голосов
/ 28 февраля 2010

Нет простого способа сделать это напрямую, однако у Son of Strike есть такая возможность. Он позволяет вам вникать во все ссылки на объекты, отслеживаемые CLR, и смотреть, какие объекты ссылаются на какой-либо конкретный объект и т. Д.

Вот хороший учебник для изучения отладки CLR через SoS .

...