Любые слабые интернирующие коллекции (для неизменяемых объектов)

В некоторых ситуациях, связанных с неизменяемыми объектами, возможно появление множества различных объектов, которые семантически идентичны. Простым примером будет чтение многих строк текста из файла в строки. С точки зрения программы, тот факт, что две строки имеют одинаковую последовательность символов, будет «совпадением», но с точки зрения программиста можно ожидать большого количества дублирования. Если многие строковые экземпляры идентичны, изменение ссылок на эти отдельные экземпляры на ссылки на один экземпляр сэкономит память, а также облегчит сравнение между ними (если две строковые ссылки указывают на одну и ту же строку, нет необходимости выполнять символьную сравнение символов для определения их идентичности).

Для некоторых сценариев может оказаться полезным предоставляемое системой средство интернирования строк. Однако имеет несколько серьезных ограничений:

Как только строка интернирована, эта интернированная копия будет жить вечно, независимо от того, существует ли какая-либо другая ссылка на нее Средство интернирования строк работает только со строками и не может использоваться с любыми другими неизменяемыми типами.

Если бы существовала настоящаяWeakDictionary<ImmutableClassType, ImmutableClassType> (для каждого элемента ключ и значение будут идентичны), код может сделать что-то вроде:

if (theDict.TryGetValue(myString, ref internedString))
  myString = internedString;
else
  theDict[myString] = myString;

К сожалению, я не знаю о каких-либо встроенныхWeakDictionary<keyType, valType> класс в .net. Кроме того, было бы бесполезно создавать слабую ссылку для ключа и значения каждого элемента, когда обе ссылки всегда указывают на одну и ту же вещь.

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

Для ситуаций, когда экземпляры класса будут иметь четко определенное время жизни, может быть разумно использовать обычныйDictionary объединить идентичные экземпляры. Однако во многих случаях бывает сложно узнать, когда такDictionary должны быть заброшены или очищены. AWeakReference-интернированная коллекция позволит избежать таких проблем. Существует ли такая вещь или ее легко реализовать?

Добавление Как заметил свик,Dictionary<WeakReference, WeakReference> было бы несколько проблематично, поскольку не было бы практического способа определитьIEqualityComparer у которого был бы живойWeakReference вернутьGetHashCode значение своей цели, и мертвые продолжают возвращать это значение. Можно определить структуру, которая будет содержать целочисленное значение target-hashcode (заданное в конструкторе) и чей собственныйGetHashCode вернет это целое число. Небольшое улучшение может заключаться в использованииConditionalWeakTable, чтобы связать цельWeakReference к финализуемому объекту, который можно использовать для постановки в очередь элементов таблицы для удаления.

Я не уверен, каков правильный баланс между попыткой вычистить словарь по сравнению с более пассивным подходом (например, выполнить проверку при добавлении элемента, если с момента последней проверки был хотя бы один GC, и количество элементов, добавленных с момента последнего сканирования, превышает количество элементов, которые его пережили). Просмотр всего в словаре не будет бесплатным, но ConditionalWeakTable, вероятно, тоже не будет бесплатным.

PPS Еще одно понятие, о котором я думал, но я подумал, что оно, вероятно, не будет столь же полезным, как подход со слабым интернированием, будет состоять в том, чтобы логически неизменяемый тип содержал изменяемое значение «временной метки» и имел метод сравнения, который принимает его аргументыref. Если два разных экземпляра окажутся равными, будут проверены значения их меток времени. Если оба равны нулю, им будут назначаться последовательные отрицательные числа из глобального счетчика (-1, -2, -3 и т. Д.). Параметр, который имел (или был назначен) более низкое значение метки времени, затем будет заменен другим.

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

Ответы на вопрос(1)

Ваш ответ на вопрос