Есть ли какой-либо предопределенный класс в .net 2.0 для хранения одного изменяемого универсального поля? - PullRequest
1 голос
/ 20 июня 2011

В ряде моих проектов я объявляю довольно скучный класс:

    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 - Примеры использования:

  1. Чтобы подсчитать, сколько раз каждая отдельная строка появляется в списке, можно создать словарь (Of String, Holder (Of Integer)), а затем для каждой строки выполнить TryGetValue, чтобы получить держатель, если он уже есть. существует. Если ничего не существует, создайте новый держатель и сохраните его в словаре. Затем в любом случае увеличьте значение, хранящееся в держателе. Обратите внимание, что для выполнения этих действий потребуется минимальное количество записей в словаре.
  2. Если у вас есть словарь неизменяемых вещей, и вы хотите изменить значение, связанное с ключом, на производное от старого значения (например, это словарь «String, String», и вы хотите эффективно выполнить «MyDict») (myKey) = myDict (key) & someThing "), выполнение такой операции путем написания словаря потребовало бы блокировки всего словаря, пока добавляется строка. Вероятно, не так уж плохо, если операция так же проста, как добавление строки, но потенциально плохо, если операция сложнее. Используя «Держатель», нужно всего лишь заблокировать словарь при получении ключа; затем можно снять блокировку словаря и заблокировать держатель, позволяя другим потокам использовать словарь.
  3. При генерации замыканий компилятор может использовать класс Holder, чтобы избежать того, чтобы делегаты сохраняли поля, которые они не собираются использовать. Если область действия содержит ExорогоObject 'foo' и целое число 'bar', и оно содержит кратковременное замыкание, которое требует как 'foo' и 'bar', так и долгоживущее, которое просто требует 'bar', компилятор может определять отдельные типы замыкания для два закрытия, и оба они включают ссылку на одного и того же держателя (Of Bar). Это позволило бы поддерживать семантику замыкания без необходимости поддерживать какие-либо дополнительные объекты.

Ответы [ 2 ]

6 голосов
/ 22 июня 2011

Я не знаю ни одного типа, который делает то, что вы хотите.

Относительно ваших трех вариантов использования:

  1. Конечно, но имейте в виду, что теперь вы торгуете повышенным давлением сбора, увеличением использования виртуальной памяти и большим количеством дополнительного времени для отслеживания набора живых объектов для уменьшенного количества накоплений целых чисел в корзинах словаря. Это хороший компромисс? Звучит не так здорово для меня. Я был бы удивлен, если бы это была большая победа.

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

  3. Ключ "компилятор может сделать два типа замыкания". Проблема, которую вы описываете, является результатом того факта, что мы не разделяем типы замыканий эффективно. Класс замыкания по сути является вашим типом «держатель», просто держится за произвольно много данных, а не только за один. (Мы рассматриваем возможность найти лучшее решение для разделения типов замыканий в C # и VB, но без обещаний.)

Все это говорит о том, что я использовал ваш трюк раньше, в основном для ситуаций, когда я переносил существующий код из C ++, который интенсивно использует передачу ссылок на переменные. Обычно я использую этот трюк, чтобы запустить и запустить перенесенный код, а затем реорганизовать его в нечто более идиоматическое C # -ish.

1 голос
/ 27 июня 2011

System.Runtime.CompilerServices.StrongBox<T>

http://msdn.microsoft.com/en-us/library/bb549038.aspx Делает именно то, что вы хотите. Это класс .NET 4 и имеет интерфейс IStrongBox, позволяющий использовать его в неизвестных случаях набора текста. (Например, вы использовали отражение для создания словаря K, StrongBox, но вы не знаете, что такое V на самом деле, поэтому вы можете изменять их как элементы IStrongBox.)

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