50

我目前使用这种方便的转换扩展方法来进行类型之间的转换:

    public static T To<T>(this IConvertible obj)
    {
        return (T)Convert.ChangeType(obj, typeof(T));
    }

但是,它不喜欢将有效值转换为 Nullable,例如,这会失败:

    "1".To<int?>();

显然,1 很容易转换为 (int?),但它得到了错误:

    Invalid cast from 'System.String' to 'System.Nullable`1[[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'.

这是一个明显简化的示例,实际上我使用它来进行字符串类型的转换,如下所示:

packageDb.Quantity = package.package.ElementDeep(Namespace + "PackageQuantity", Namespace + "ActualQuantity", Namespace + "Quantity").ValueOrNull().To<int?>();

如果 Convert.ChangeType 不喜欢 Nullable,那么有人有什么好主意吗?

4

8 回答 8

99
public static T To<T>(this IConvertible obj)
{
    Type t = typeof(T);
    Type u = Nullable.GetUnderlyingType(t);

    if (u != null)
    {
        return (obj == null) ? default(T) : (T)Convert.ChangeType(obj, u);
    }
    else
    {
        return (T)Convert.ChangeType(obj, t);
    }
}
于 2009-04-27T14:55:52.473 回答
4
public static T To<T>(this IConvertible obj) 
{
    Type t = typeof(T);
    if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>))
        t = t.GetGenericArguments()[0];

    return (T)Convert.ChangeType(obj, t); 
}

但是如果转换失败,它会抛出一个异常,而不是像预期的那样返回 null。

于 2009-04-27T14:47:30.183 回答
3

我结束了这个

private static T To<T>(this Object @object, Boolean returnDefaultOnException)
{
    Type type = typeof(T);
    Type underlyingTypeOfNullable = Nullable.GetUnderlyingType(type);
    try
    {
        return (T) Convert.ChangeType(@object, underlyingTypeOfNullable ?? type);
    }
    catch (Exception exception)
    {
        if (returnDefaultOnException)
            return default(T);
        String typeName = type.Name;
        if (underlyingTypeOfNullable != null)
            typeName += " of " + underlyingTypeOfNullable.Name;
        throw new InvalidCastException("Object can't be cast to " + typeName, exception);

    }
}
public static T To<T>(this Object @object) { return @object.To<T>(returnDefaultOnException: false); }
public static T ToOrDefault<T>(this Object @object) { return @object.To<T>(returnDefaultOnException: true); }

它的行为类似于 LINQ 扩展方法Singleand SingleOrDefaultand Firstand FirstOrDefault

简而言之,To<T>()尝试转换并在失败时抛出,同时ToOrDefault<T>()尝试转换并在失败时返回default(T)

于 2012-12-13T19:11:18.253 回答
2

卢克的解决方案对我有好处(显然得到了他的支持)但我以这种方式为我简化了它

    private static Type ResolveType(String typeName)
    {
        Type t = Type.GetType(typeName);
        if (t == null)
            return null;

        Type u = Nullable.GetUnderlyingType(t);

        if (u != null) {
            t = u;
        }
        return t;
    }

因为我从一个字符串而不是从一个类型开始......想法?

于 2011-01-12T17:33:29.083 回答
2

也许我错过了这一点,但在 Nullable 的实例中,您的方法如何提供比简单强制转换(如?)的可读性、性能或维护优势(int?)1

除此之外,也许还有另一种扩展方法?

public static T? ToNullable<T>(this T obj) where T:struct
{
    return (T?)obj;
}

编辑

在查看了您的编辑后,为什么我提供的通用函数不能替代您To<T>在该代码行中的函数?您不能允许任何类型转换为 Nullable (这就是为什么ChangeType不起作用),因为该泛型只接受值类型。您要么必须使用像我提供的那样的函数,要么将您的签名更改To<T>为仅接受值类型并为Nullable<T>.

于 2009-04-27T14:24:02.020 回答
1

这是我目前使用的方法(我在SO上得到了答案),它从字符串转换为可空类型:

    public static Nullable<T> ConvertToNullable<T>(this string s) where T : struct
    {
        if (!string.IsNullOrEmpty(s.Trim()))
        {
            TypeConverter conv = TypeDescriptor.GetConverter(typeof(Nullable<>).MakeGenericType(typeof(T)));
            return (Nullable<T>)conv.ConvertFrom(s);
        }
        return null;
    }
于 2009-04-27T14:36:05.343 回答
0

此方法可以满足您的需要,并且在执行时看起来不错。

    /// <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/tree/master/src/StringExtensions

于 2017-02-24T19:06:50.760 回答
0

扩展@LukeH 代码:

public static T GetValue<T>(string Literal, T DefaultValue)
    {
        if (Literal == null || Literal == "" || Literal == string.Empty) return DefaultValue;
        IConvertible obj = Literal;
        Type t = typeof(T);
        Type u = Nullable.GetUnderlyingType(t);

        if (u != null)
        {
            return (obj == null) ? DefaultValue : (T)Convert.ChangeType(obj, u);
        }
        else
        {
            return (T)Convert.ChangeType(obj, t);
        }
    }
于 2016-05-18T09:52:10.577 回答