В ряде моих проектов я объявляю довольно скучный класс:
Class Holder(Of T)
Public It As T
Sub New(ByVal It As T)
Me.It = It
End Sub
End Class
например позволяют объекту передавать информацию другому объекту таким образом, что информация может быть видоизменена позже, где бы она ни находилась. Например, в словаре (Of String, Holder (Of SomeImmutableType)) можно обновить элемент SomeImmutableType без необходимости изменения самого словаря (поскольку запись словаря для данного ключа всегда будет содержать один и тот же объект Holder, этот Holder объект может быть использован как замок).
Есть ли какой-нибудь встроенный класс, который был бы более подходящим для этой цели? Я бы предпочел совместимость с .net 2.0, но даже в 4.0 тип Tuple неизменен. Если такого встроенного элемента нет, лучше ли для каждого типа, которому требуется тип Holder, определять его как вложенный тип, или требовать, чтобы в проекте было одно определение Holder?
Единственная встроенная вещь, о которой я знаю, это Array. Использование массива из одного элемента будет работать, но это выглядит очень странно, поскольку обычно, когда код имеет массив, ожидается, что он будет использоваться с размером, отличным от единицы.
PS - Примеры использования:
- Чтобы подсчитать, сколько раз каждая отдельная строка появляется в списке, можно создать словарь (Of String, Holder (Of Integer)), а затем для каждой строки выполнить TryGetValue, чтобы получить держатель, если он уже есть. существует. Если ничего не существует, создайте новый держатель и сохраните его в словаре. Затем в любом случае увеличьте значение, хранящееся в держателе. Обратите внимание, что для выполнения этих действий потребуется минимальное количество записей в словаре.
- Если у вас есть словарь неизменяемых вещей, и вы хотите изменить значение, связанное с ключом, на производное от старого значения (например, это словарь «String, String», и вы хотите эффективно выполнить «MyDict») (myKey) = myDict (key) & someThing "), выполнение такой операции путем написания словаря потребовало бы блокировки всего словаря, пока добавляется строка. Вероятно, не так уж плохо, если операция так же проста, как добавление строки, но потенциально плохо, если операция сложнее. Используя «Держатель», нужно всего лишь заблокировать словарь при получении ключа; затем можно снять блокировку словаря и заблокировать держатель, позволяя другим потокам использовать словарь.
- При генерации замыканий компилятор может использовать класс Holder, чтобы избежать того, чтобы делегаты сохраняли поля, которые они не собираются использовать. Если область действия содержит ExорогоObject
'foo' и целое число 'bar', и оно содержит кратковременное замыкание, которое требует как 'foo' и 'bar', так и долгоживущее, которое просто требует 'bar', компилятор может определять отдельные типы замыкания для два закрытия, и оба они включают ссылку на одного и того же держателя (Of Bar). Это позволило бы поддерживать семантику замыкания без необходимости поддерживать какие-либо дополнительные объекты.