将字符串转换为可空类型(int、 double 等)

我正在尝试进行一些数据转换。不幸的是,大部分数据都是字符串,应该是 int 或 double 等等。.

所以我得到的是这样的东西:

double? amount = Convert.ToDouble(strAmount);

这种方法的问题是,如果 strAmount 是空的,如果它是空的,我希望它的金额为 null,所以当我将它添加到数据库中时,列将为 null。所以我最后写道:

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;
}
}

但是我得到了一个错误: 不能将类型‘ string’转换为‘ T’吗

有没有解决这个问题的方法? 我不是很熟悉使用泛型创建方法。

150675 次浏览

没有别的办法了。Nullable 和您的方法一样,只能使用值类型作为参数。String 是引用类型,因此与此声明不兼容。

你可以试试:

TypeConverter conv = TypeDescriptor.GetConverter(typeof(int));
conv.ConvertFrom(mystring);

执行您自己的 null 检查并在必要时返回 int?

这个怎么样:


double? amount = string.IsNullOrEmpty(strAmount) ? (double?)null : Convert.ToDouble(strAmount);

Of course, this doesn't take into account the convert failing.

另一件需要记住的事情是字符串本身可能为空。

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>();
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;
}
}
}

试试这个。

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);
}

我编写了这个通用类型转换器。它使用 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;
}
}

我喜欢乔尔的回答,但我稍微修改了一下,因为我不喜欢吃异常。

    /// <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;
}
}

有一个通用的解决方案(对于任何类型)。可用性是好的,但实现应该得到改进: 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>();

您可以对对象使用以下内容,但不幸的是,这对字符串不起作用。

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

匿名类型的例子:

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>));

这里有一些基于公认答案的东西。我删除了 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>);
}

让我们在堆栈中添加一个类似的解决方案。这个解决方案也解析枚举,它看起来很好。非常安全。

/// <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

另一个变种,这个

  • 不接受例外情况
  • 如果类型无法从 string转换,则引发 NotSupportedException。例如,没有类型转换器的自定义结构。
  • 否则,如果字符串无法解析,则返回 (T?)null。不需要检查 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;
}

Joel Coehoorn”提供的一般答案是好的。

但是,这是另一种不使用那些 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