Более быстрая версия Convert.ChangeType

В приложении, которое у меня есть, я делаю довольно частые вызовы Convert.ChangeType, чтобы преобразовать значение в динамически загруженный тип.

Однако после профилирования с ANTS я обнаружил, что этот Convert.ChangeType, кажется, занимает значительную часть времени (из-за того, что его часто называют). У кого-нибудь есть более быстрая альтернатива этому?

В этот момент у меня есть объект типа, содержащий цель, и string, содержащий значение.

Ниже приведен код нарушения. Я рассматривал возможность использования switch-statement для типа (поскольку это ограниченный набор типов) и вызов методов анализа, хотя я не уверен, будет ли это быстрее.

if(attributeRow["Value"]!=DBNull.Value)
    sample[attr] = attr.AttributeType == typeof(Guid)
                 ? new Guid(attributeRow["Value"].ToString())
                 : (IComparable)Convert.ChangeType(attributeRow["Value"],attr.AttributeType);

Ответ 1

Я не знаю каких-либо других функций внутри самой рамки для изменения типов, отличных от функции Convert.ChangeType (и явно выражений).

Для этого я считаю, что единственным другим способом улучшить это является сворачивание вашей собственной функции ChangeType, которая специально оптимизирована для вашей конкретной ситуации (если это возможно).

Вы упоминаете, что работаете с ограниченным количеством типов, возможно, вы имеете дело с одним типом больше, чем с другими? Таким образом, ваша функция ChangeType может быть оптимизирована, чтобы сначала попытаться выполнить это конкретное преобразование, и только пробовать других, если они не работают. Вы упомянули попытку блока кода в стиле коммутатора, и к этому может быть применен тот же подход (например, наиболее часто используемый тип "Первый" ). Что касается того, будет ли оно быстрее, это будет зависеть от ваших данных, которые вы обрабатываете (и частоты/изменчивости типов, которые вы конвертируете в/из), и единственным реальным способом измерения этого является попытка и его профилирование сравнение с методологией Convert.ChangeType.

Одна интересная ссылка, если вы хотите использовать свои собственные функции, находится в блоге Peter Johnson:

Convert.ChangeType не обрабатывает nullables

Обязательно прочитайте также все комментарии к сообщению.

Ответ 2

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

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

Я все еще возвращаюсь к ChangeType, но я стараюсь отказаться от него как можно раньше.

public static T? ToOrDefault<T>(object value)
    where T : struct, IConvertible
{
    var x = value as T?;
    if (x.HasValue)
    {
        return x;
    }
    if (value == null || Convert.IsDBNull(value))
    {
        return null;
    }
    try
    {
        return (T)Convert.ChangeType(value, typeof(T), CultureInfo.InvariantCulture);
    }
    catch (InvalidCastException)
    {
    }
    catch (FormatException)
    {
    }
    catch (OverflowException)
    {
    }
    catch (ArgumentException)
    {
    }
    return default(T?);
}

Ответ 3

Вы можете перевернуть свою собственную функцию ChangeType, которая просто выполняет статичное кастинг C-стиля. Это будет мой подход.

Ответ 4

Я не тестировал, если быстрее, но это альтернативный способ динамического кастинга. Это alsp более универсально, поскольку Convert.ChangeType() имеет некоторые ограничения, как вы видели (Гиды, Нулевые типы)

value = (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromInvariantString(str);

Ответ 5

Я знаю, это звучит безумно, но вы можете использовать Newtonsoft JSON.NET, чтобы преобразовать ваш объект в сериализованную строку и затем привести ее из любого другого типа.

var jsontemp = JsonConvert.SerializeObject(anyObject);
var ConvertedObject = JsonConvert.DeserializeObject(jsontemp, desiredType);