Кто-нибудь знает быстрый способ в VB перейти от строки к универсальному типу T, ограниченному типом значения (Of T as Structure), когда я знаю, что T всегда будет некоторым числовым типом?
Это слишком медленно, на мой вкус:
Return DirectCast(Convert.ChangeType(myStr, GetType(T)), T)
Но, похоже, это единственный разумный способ получить от String --> T. Я пытался использовать Reflector, чтобы увидеть, как работает Convert.ChangeType, и хотя я могу преобразовать String в заданный числовой тип с помощью взломанной версии этого кода, я понятия не имею, как втиснуть этот тип обратно в T, чтобы он мог быть возвращены.
Я добавлю, что часть снижения скорости, которую я вижу (в цикле синхронизации), связана с тем, что возвращаемое значение присваивается значению Nullable(Of T). Если я строго типизирую свой класс для определенного числового типа (например, UInt16), то я могу значительно повысить производительность, но тогда класс нужно будет дублировать для каждого числового типа, который я использую.
Было бы почти неплохо, если бы был конвертер в/из T во время работы над ним в общем методе/классе. Может есть, а я не замечаю его существования?
Заключение.
При тестировании трех приведенных ниже реализаций и моей исходной формы DirectCast/ChangeType подход @peenut к использованию подготовленного делегата для извлечения метода Parse из базового типа работает. Однако проверка ошибок не выполняется, поэтому разработчики должны помнить, что это следует использовать только с теми типами значений, для которых доступен метод Parse. Или расширьте приведенное ниже, чтобы выполнить проверку ошибок.
Все прогоны проводились на 32-битной системе под управлением Windows Server 2003 R2 с 4 ГБ оперативной памяти. Каждый «прогон» — это 1 000 000 выполнений (операций) тестируемого метода, синхронизированных с помощью StopWatch и сообщаемых в миллисекундах.
Оригинал DirectCast(Convert.ChangeType(myStr, GetType(T)), T):
1000000 ops: 597ms
Average of 1000000 ops over 10 runs: 472ms
Average of 1000000 ops over 10 runs: 458ms
Average of 1000000 ops over 10 runs: 453ms
Average of 1000000 ops over 10 runs: 466ms
Average of 1000000 ops over 10 runs: 462ms
Использование System.Reflection и вызов InvokeMethod для доступа к методу Parse:
1000000 ops: 12213ms
Average of 1000000 ops over 10 runs: 11468ms
Average of 1000000 ops over 10 runs: 11509ms
Average of 1000000 ops over 10 runs: 11524ms
Average of 1000000 ops over 10 runs: 11509ms
Average of 1000000 ops over 10 runs: 11490ms
Подход Конрада к генерации кода IL для доступа к методу Parse и сохранения вызова в делегате:
1000000 ops: 352ms
Average of 1000000 ops over 10 runs: 316ms
Average of 1000000 ops over 10 runs: 315ms
Average of 1000000 ops over 10 runs: 314ms
Average of 1000000 ops over 10 runs: 314ms
Average of 1000000 ops over 10 runs: 314ms
Подход peenut к использованию делегата для прямого доступа к методу Parse:
1000000 ops: 272ms
Average of 1000000 ops over 10 runs: 272ms
Average of 1000000 ops over 10 runs: 275ms
Average of 1000000 ops over 10 runs: 274ms
Average of 1000000 ops over 10 runs: 272ms
Average of 1000000 ops over 10 runs: 273ms
Для сравнения, подход Пината почти на 200 мс быстрее при выполнении 1 000 000 раз в узком цикле, поэтому его подход выигрывает. Хотя Конрад не отставал и сам по себе является захватывающим исследованием таких вещей, как ILGenerator. Реквизит всем, кто внес свой вклад!