Я пытаюсь преобразовать данные. К сожалению, большая часть данных находится в строках, где они должны быть int или double и т. Д.
Итак, у меня есть что-то вроде:
double? amount = Convert.ToDouble(strAmount);
Проблема с этим подходом заключается в том, что если strAmount пуст, если он пуст, я хочу, чтобы сумма была равна нулю, поэтому, когда я добавляю его в базу данных, столбец будет нулевым. В итоге я написал следующее:
double? amount = null;
if(strAmount.Trim().Length>0)
{
amount = Convert.ToDouble(strAmount);
}
Теперь это работает нормально, но теперь у меня пять строк кода вместо одной. Это затрудняет чтение, особенно когда мне нужно преобразовать большое количество столбцов.
Я думал, что использую расширение для строкового и универсального классов для передачи типа, потому что это может быть double, int или long. Итак, я попробовал это:
public static class GenericExtension
{
public static Nullable<T> ConvertToNullable<T>(this string s, T type) where T: struct
{
if (s.Trim().Length > 0)
{
return (Nullable<T>)s;
}
return null;
}
}
Но я получаю сообщение об ошибке: не удается преобразовать строку типа в T?
Есть ли способ обойти это? Я не очень знаком с созданием методов с использованием дженериков.
источник
Ответы:
Также следует иметь в виду, что сама строка может быть нулевой.
public static Nullable<T> ToNullable<T>(this string s) where T: struct { Nullable<T> result = new Nullable<T>(); try { if (!string.IsNullOrEmpty(s) && s.Trim().Length > 0) { TypeConverter conv = TypeDescriptor.GetConverter(typeof(T)); result = (T)conv.ConvertFrom(s); } } catch { } return result; }
источник
Вы можете попробовать использовать следующий метод расширения:
public static T? GetValueOrNull<T>(this string valueAsString) where T : struct { if (string.IsNullOrEmpty(valueAsString)) return null; return (T) Convert.ChangeType(valueAsString, typeof(T)); }
Таким образом вы можете сделать это:
double? amount = strAmount.GetValueOrNull<double>(); int? amount = strAmount.GetValueOrNull<int>(); decimal? amount = strAmount.GetValueOrNull<decimal>();
источник
Как насчет этого:
double? amount = string.IsNullOrEmpty(strAmount) ? (double?)null : Convert.ToDouble(strAmount);
Конечно, при этом не учитывается сбой конвертации.
источник
Я написал этот универсальный преобразователь типов. Он работает с значениями Nullable и стандартными значениями, конвертируя между всеми конвертируемыми типами, а не только строкой. Он обрабатывает все возможные сценарии (значения по умолчанию, нулевые значения, другие значения и т. Д.)
Я использую его около года в десятках производственных программ, так что он должен быть довольно надежным.
public static T To<T>(this IConvertible obj) { Type t = typeof(T); if (t.IsGenericType && (t.GetGenericTypeDefinition() == typeof(Nullable<>))) { if (obj == null) { return (T)(object)null; } else { return (T)Convert.ChangeType(obj, Nullable.GetUnderlyingType(t)); } } else { return (T)Convert.ChangeType(obj, t); } } public static T ToOrDefault<T> (this IConvertible obj) { try { return To<T>(obj); } catch { return default(T); } } public static bool ToOrDefault<T> (this IConvertible obj, out T newObj) { try { newObj = To<T>(obj); return true; } catch { newObj = default(T); return false; } } public static T ToOrOther<T> (this IConvertible obj, T other) { try { return To<T>(obj); } catch { return other; } } public static bool ToOrOther<T> (this IConvertible obj, out T newObj, T other) { try { newObj = To<T>(obj); return true; } catch { newObj = other; return false; } } public static T ToOrNull<T> (this IConvertible obj) where T : class { try { return To<T>(obj); } catch { return null; } } public static bool ToOrNull<T> (this IConvertible obj, out T newObj) where T : class { try { newObj = To<T>(obj); return true; } catch { newObj = null; return false; } }
источник
OutOfMemoryException
если вы не можете сузить его до фиксированного набора типов исключений.Вы можете попробовать:
TypeConverter conv = TypeDescriptor.GetConverter(typeof(int)); conv.ConvertFrom(mystring);
сделайте свою собственную нулевую проверку и верните
int?
при необходимости. Вы также захотите обернуть это вtry {}
источник
Попробуйте это ...
public delegate bool TryParseDelegate<T>(string data, out T output); public static T? ToNullablePrimitive<T>(this string data, TryParseDelegate<T> func) where T:struct { string.IsNullOrEmpty(data) return null; T output; if (func(data, out output)) { return (T?)output; } return null; }
Тогда назовите это так ...
void doStuff() { string foo = "1.0"; double? myDouble = foo.ToNullablePrimitive<double>(double.TryParse); foo = "1"; int? myInt = foo.ToNullablePrimitive<int>(int.TryParse); foo = "haha"; int? myInt2 = foo.ToNullablePrimitive<int>(int.TryParse); }
источник
Мне нравится ответ Джоэла, но я немного изменил его, так как не люблю есть исключения.
/// <summary> /// Converts a string to the specified nullable type. /// </summary> /// <typeparam name="T">The type to convert to</typeparam> /// <param name="s">The string to convert</param> /// <returns>The nullable output</returns> public static T? ToNullable<T>(this string s) where T : struct { if (string.IsNullOrWhiteSpace(s)) return null; TypeConverter conv = TypeDescriptor.GetConverter(typeof (T)); return (T) conv.ConvertFrom(s); } /// <summary> /// Attempts to convert a string to the specified nullable primative. /// </summary> /// <typeparam name="T">The primitive type to convert to</typeparam> /// <param name="data">The string to convert</param> /// <param name="output">The nullable output</param> /// <returns> /// True if conversion is successfull, false otherwise. Null and whitespace will /// be converted to null and return true. /// </returns> public static bool TryParseNullable<T>(this string data, out T? output) where T : struct { try { output = data.ToNullable<T>(); return true; } catch { output = null; return false; } }
источник
Вы можете использовать следующее с объектами, но, к сожалению, это не работает со строками.
double? amount = (double?)someObject;
Я использую его для обертывания переменной сеанса в свойстве (на базовой странице) .. так что мое фактическое использование (на моей базовой странице):
public int? OrganisationID { get { return (int?)Session[Constants.Session_Key_OrganisationID]; } set { Session[Constants.Session_Key_OrganisationID] = value; } }
Я могу проверить наличие null в логике страницы:
if (base.OrganisationID == null) // do stuff
источник
CType(Object, Nullable(Of Double))
отлично работает со строкамиНет никакого способа обойти это. Nullable, как и ваш метод, ограничивается использованием только типов значений в качестве аргумента. String является ссылочным типом и поэтому несовместим с этим объявлением.
источник
public static class GenericExtension { public static T? ConvertToNullable<T>(this String s) where T : struct { try { return (T?)TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(s); } catch (Exception) { return null; } } }
источник
Есть универсальное решение (на любой тип). Удобство использования хорошее, но реализация должна быть улучшена: http://cleansharp.de/wordpress/2011/05/generischer-typeconverter/
Это позволяет вам писать очень чистый код, например:
string value = null; int? x = value.ConvertOrDefault<int?>();
а также:
object obj = 1; string value = null; int x = 5; if (value.TryConvert(out x)) Console.WriteLine("TryConvert example: " + x); bool boolean = "false".ConvertOrDefault<bool>(); bool? nullableBoolean = "".ConvertOrDefault<bool?>(); int integer = obj.ConvertOrDefault<int>(); int negativeInteger = "-12123".ConvertOrDefault<int>(); int? nullableInteger = value.ConvertOrDefault<int?>(); MyEnum enumValue = "SecondValue".ConvertOrDefault<MyEnum>(); MyObjectBase myObject = new MyObjectClassA(); MyObjectClassA myObjectClassA = myObject.ConvertOrDefault<MyObjectClassA>();
источник
typeName.IndexOf
? Действительно?) И странного поведения (показаннаяTryConvert
функция даже не обрабатывает нулевые значения правильно).Вот что-то, основанное на принятом ответе. Я удалил команду try / catch, чтобы убедиться, что все исключения не проглочены и не обработаны. Также убедитесь, что возвращаемая переменная (в принятом ответе) никогда не инициализируется дважды даром.
public static Nullable<T> ToNullable<T>(this string s) where T: struct { if (!string.IsNullOrWhiteSpace(s)) { TypeConverter conv = TypeDescriptor.GetConverter(typeof(T)); return (T)conv.ConvertFrom(s); } return default(Nullable<T>); }
источник
Мой пример для анонимных типов:
private object ConvertNullable(object value, Type nullableType) { Type resultType = typeof(Nullable<>).MakeGenericType(nullableType.GetGenericArguments()); return Activator.CreateInstance(resultType, Convert.ChangeType(value, nullableType.GetGenericArguments()[0])); } ... Type anonimousType = typeof(Nullable<int>); object nullableInt1 = ConvertNullable("5", anonimousType); // or evident Type Nullable<int> nullableInt2 = (Nullable<int>)ConvertNullable("5", typeof(Nullable<int>));
источник
Еще одна вариация. Вот этот
NotSupportedException
если тип не может быть преобразован изstring
. Например, настраиваемая структура без преобразователя типов.(T?)null
если строку не удалось проанализировать. Нет необходимости проверять нуль или пробел.using System.ComponentModel; public static Nullable<T> ToNullable<T>(this string s) where T : struct { var ret = new Nullable<T>(); var conv = TypeDescriptor.GetConverter(typeof(T)); if (!conv.CanConvertFrom(typeof(string))) { throw new NotSupportedException(); } if (conv.IsValid(s)) { ret = (T)conv.ConvertFrom(s); } return ret; }
источник
Добавим в стек еще одно подобное решение. Этот также анализирует перечисления, и это выглядит красиво. Очень безопасно.
/// <summary> /// <para>More convenient than using T.TryParse(string, out T). /// Works with primitive types, structs, and enums. /// Tries to parse the string to an instance of the type specified. /// If the input cannot be parsed, null will be returned. /// </para> /// <para> /// If the value of the caller is null, null will be returned. /// So if you have "string s = null;" and then you try "s.ToNullable...", /// null will be returned. No null exception will be thrown. /// </para> /// <author>Contributed by Taylor Love (Pangamma)</author> /// </summary> /// <typeparam name="T"></typeparam> /// <param name="p_self"></param> /// <returns></returns> public static T? ToNullable<T>(this string p_self) where T : struct { if (!string.IsNullOrEmpty(p_self)) { var converter = System.ComponentModel.TypeDescriptor.GetConverter(typeof(T)); if (converter.IsValid(p_self)) return (T)converter.ConvertFromString(p_self); if (typeof(T).IsEnum) { T t; if (Enum.TryParse<T>(p_self, out t)) return t;} } return null; }
https://github.com/Pangamma/PangammaUtilities-CSharp/blob/master/PangammaUtilities/Extensions/ToNullableStringExtension.cs
источник
Общий ответ Джоэла Кохорна хорош.
Но это другой способ без использования тех
GetConverter...
или иныхtry/catch
блоков ... (я не уверен, но в некоторых случаях это может иметь лучшую производительность):public static class StrToNumberExtensions { public static short ToShort(this string s, short defaultValue = 0) => short.TryParse(s, out var v) ? v : defaultValue; public static int ToInt(this string s, int defaultValue = 0) => int.TryParse(s, out var v) ? v : defaultValue; public static long ToLong(this string s, long defaultValue = 0) => long.TryParse(s, out var v) ? v : defaultValue; public static decimal ToDecimal(this string s, decimal defaultValue = 0) => decimal.TryParse(s, out var v) ? v : defaultValue; public static float ToFloat(this string s, float defaultValue = 0) => float.TryParse(s, out var v) ? v : defaultValue; public static double ToDouble(this string s, double defaultValue = 0) => double.TryParse(s, out var v) ? v : defaultValue; public static short? ToshortNullable(this string s, short? defaultValue = null) => short.TryParse(s, out var v) ? v : defaultValue; public static int? ToIntNullable(this string s, int? defaultValue = null) => int.TryParse(s, out var v) ? v : defaultValue; public static long? ToLongNullable(this string s, long? defaultValue = null) => long.TryParse(s, out var v) ? v : defaultValue; public static decimal? ToDecimalNullable(this string s, decimal? defaultValue = null) => decimal.TryParse(s, out var v) ? v : defaultValue; public static float? ToFloatNullable(this string s, float? defaultValue = null) => float.TryParse(s, out var v) ? v : defaultValue; public static double? ToDoubleNullable(this string s, double? defaultValue = null) => double.TryParse(s, out var v) ? v : defaultValue; }
Использование следующее:
var x1 = "123".ToInt(); //123 var x2 = "abc".ToInt(); //0 var x3 = "abc".ToIntNullable(); // (int?)null int x4 = ((string)null).ToInt(-1); // -1 int x5 = "abc".ToInt(-1); // -1 var y = "19.50".ToDecimal(); //19.50 var z1 = "invalid number string".ToDoubleNullable(); // (double?)null var z2 = "invalid number string".ToDoubleNullable(0); // (double?)0
источник
TypeDescriptor.GetConverter
... кодов. Это просто другой способ.