Полный отказ от ответственности, этот код не на 100% мой код. Я вносил в него изменения на протяжении многих лет, хотя я не уверен, кому приписать основу. С учетом этого, как молодого разработчика, одним из моих самых больших страхов была необходимость преобразования строки в int, строки в DateTime или любую из тысячи с лишним комбинаций, которые могут возникнуть.

С включением Generics в C# эта проблема быстро стала простой задачей, которая меня не так сильно пугала. Я наткнулся на фрагмент кода, частично приведенный ниже, который быстро стал одной из первых вещей, которые я импортирую в любую новую программу на C#. Этот единственный фрагмент кода значительно сократил количество строк кода, которые я пишу в приложении. Иногда порядка тысячи строк кода. Позвольте мне объяснить, почему.

Скажем, я хочу преобразовать строку «1234» в int 1234. Это можно сделать разными способами. Мы можем сделать что-то вроде этого:

try
{
    var retVal = Int32.Parse(input);
} //end try
catch(Exception ex)
{
    //log the error
} //end catch

Хотя это немного многословно. Для этого требуется блок try/catch, поскольку Int32.Parse терпит неудачу в менее изящном поместье.

Мы можем очистить это, выполнив следующие действия:

var retVal = 0;

Int32.TryParse(input, out retVal);

Это делает код немного чище и изящно завершает работу, хотя это все еще две строки кода, что просто недостаточно. :)

Мы можем сделать это еще более ясным и лаконичным, введя статический метод, который я называю TryConvertTo, и он выглядит так:

public static T TryConvertTo<T>(this object value)
{
    try
    {
        if ((typeof(T)) == typeof(Guid))
        {
             return (T)Convert.ChangeType(value.ToString().TryConvertToGuid(), typeof(T));
        } //end if
        return (T)Convert.ChangeType(value, typeof(T));
    } //end try
    catch (Exception ex)
    {
        return default(T);
    } //end catch
} //end TryConverTo<>
public static Guid TryConvertToGuid(this object value)
{
    try
    {
        return new Guid(value.ToString());
    } //end try
    catch (Exception ex)
    {
        return default(Guid);
    } //end catch
} //end TryConverToGuid

Приведенный выше фрагмент кода принимает переменную любого типа, пытается преобразовать ее в запрошенный тип и, если это не удается, возвращает тип по умолчанию для запрошенного преобразования. Нет больше проверки на null, нет необходимости оборачивать все преобразования в блоки try/catch, а результаты согласованы в том смысле, что вы получаете преобразованное значение или значение по умолчанию.

Например, если мы передадим строку «123abc» и попросим преобразовать ее в целое число, мы вернем 0, поскольку 0 является значением по умолчанию для целого числа. Это позволяет нам проверять наличие 0 в более поздних блоках после того, как происходит диалог, если мы хотим иметь расходящуюся логику для неудачных преобразований. Я предпочитаю этот метод, так как использование блока try/catch для логики маршрутизации обычно не одобряется.

Итак, как вы используете этот код? В любое время, когда вы хотите преобразовать объект в любой другой объект, вы можете просто вызвать .TryConvertTo‹T›() для базового объекта. Подробнее см. ниже.

//returns an int 123
int someInt = "123".TryConvertTo<int>();
//returns a double 123.0
double someDouble = "123".TryConvertTo<double>();
//returns an int 0 because the conversion will fail
int someBadInt = "123abc".TryConvertTo<int>();

Обычно var было бы достаточно, но чтобы проиллюстрировать, что вы действительно получаете преобразованное значение, в приведенном выше коде было использовано сильное приведение типов. Использование этого статического метода позволяет быстро преобразовывать «на лету», регистрировать плохие результаты в статическом классе в согласованном поместье, легко изменять логику на основе возвращаемого значения и, что более важно, преобразовывать значения в одной строке кода.