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

Nat*_*oop 135 .net c# generics extension-methods type-conversion

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

所以我得到的是:

double? amount = Convert.ToDouble(strAmount);
Run Code Online (Sandbox Code Playgroud)

这种方法的问题是如果strAmount是空的,如果它是空的我希望它等于null,所以当我将它添加到数据库时,该列将为null.所以我最后写了这个:

double? amount = null;
if(strAmount.Trim().Length>0)
{
    amount = Convert.ToDouble(strAmount);
}
Run Code Online (Sandbox Code Playgroud)

现在这个工作正常,但我现在有五行代码而不是一行代码.这使得事情变得更难以阅读,特别是当我有大量的列要转换时.

我以为我会使用字符串类和泛型的扩展来传入类型,这是因为它可能是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;
    }
}
Run Code Online (Sandbox Code Playgroud)

但我收到错误:无法将类型'string'转换为'T?'

有没有解决的办法?我不太熟悉使用泛型创建方法.

Joe*_*orn 151

要记住的另一件事是字符串本身可能为null.

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 如果使用.Net4,可以使用string.IsNullOrWhiteSpace()简化一下 (19认同)
  • 您可以省略"T type"参数,因为它没有被使用. (2认同)

Mic*_*ows 53

您可以尝试使用以下扩展方法:

public static T? GetValueOrNull<T>(this string valueAsString)
    where T : struct 
{
    if (string.IsNullOrEmpty(valueAsString))
        return null;
    return (T) Convert.ChangeType(valueAsString, typeof(T));
}
Run Code Online (Sandbox Code Playgroud)

这样你可以这样做:

double? amount = strAmount.GetValueOrNull<double>();
int? amount = strAmount.GetValueOrNull<int>();
decimal? amount = strAmount.GetValueOrNull<decimal>();
Run Code Online (Sandbox Code Playgroud)

  • 实际上..这个解决方案不起作用.changetype不会转换为可空类型.而是使用typeconverter (4认同)
  • 恕我直言,这是解决问题的最优雅方案 (3认同)

Joh*_*aft 25

那这个呢:


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

当然,这并没有考虑转换失败.


The*_*edi 22

我写了这个泛型转换器.它适用于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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 我不认为忽略所有转换错误是正确的做法.你也许不应该吞下各种例外.如果你不能将它缩小到一组固定的异常类型,至少重新抛出`OutOfMemoryException`. (2认同)

And*_*ock 9

您可能想尝试:

TypeConverter conv = TypeDescriptor.GetConverter(typeof(int));
conv.ConvertFrom(mystring);
Run Code Online (Sandbox Code Playgroud)

做你自己的空检查并int?在必要时返回.你还想把它包装成一个try {}


Ada*_*son 6

试一试......

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;
}
Run Code Online (Sandbox Code Playgroud)

然后像这样称呼它......

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);
}
Run Code Online (Sandbox Code Playgroud)


小智 5

我喜欢Joel的回答,但我对它进行了一些修改,因为我不喜欢吃异常.

    /// <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;
        }
    }
Run Code Online (Sandbox Code Playgroud)


Sco*_*NET 5

您可以将以下内容与对象一起使用,但不幸的是,这不适用于字符串.

double? amount = (double?)someObject;
Run Code Online (Sandbox Code Playgroud)

我用它来包装属性中的会话变量(在基页上)..所以我的实际用法是(在我的基页中):

public int? OrganisationID
{
    get { return (int?)Session[Constants.Session_Key_OrganisationID]; }
    set { Session[Constants.Session_Key_OrganisationID] = value; }
}
Run Code Online (Sandbox Code Playgroud)

我能够在页面逻辑中检查null:

if (base.OrganisationID == null)
    // do stuff
Run Code Online (Sandbox Code Playgroud)