C# 如何解决此问题以进行到Nullable的泛型转换<;T>;?

C# 如何解决此问题以进行到Nullable的泛型转换<;T>;?,c#,nullable,C#,Nullable,我目前使用这个方便的转换扩展方法在类型之间进行转换: public static T To<T>(this IConvertible obj) { return (T)Convert.ChangeType(obj, typeof(T)); } 这是一个明显简化的示例,实际上我正在使用它从字符串类型进行转换,如下所示: packageDb.Quantity = package.package.ElementDeep(Namespace + "P

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

    public static T To<T>(this IConvertible obj)
    {
        return (T)Convert.ChangeType(obj, typeof(T));
    }
这是一个明显简化的示例,实际上我正在使用它从字符串类型进行转换,如下所示:

packageDb.Quantity = package.package.ElementDeep(Namespace + "PackageQuantity", Namespace + "ActualQuantity", Namespace + "Quantity").ValueOrNull().To<int?>();
packageDb.Quantity=package.package.ElementDeep(名称空间+“PackageQuantity”,名称空间+“ActualQuantity”,名称空间+“Quantity”).ValueOrNull().To();

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

也许我没有抓住要点,但是在Nullable的例子中,与简单的强制转换(如
(int?)1
)相比,您的方法如何提供可读性、性能或维护优势

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

public static T? ToNullable<T>(this T obj) where T:struct
{
    return (T?)obj;
}
publicstatict?tonulable(这个T对象),其中T:struct
{
返回(T?)obj;
}
编辑


在查看您的编辑后,为什么我提供的泛型函数不能替代该行代码中的
to
函数?对于任何类型,都不能允许将其转换为Nullable(这就是为什么
ChangeType
不起作用),因为该泛型只接受值类型。您必须使用类似于我提供的函数,或者将签名
更改为
以仅接受值类型,并为
可空

添加一个特例。这是我当前使用的方法(我得到了答案),它将字符串转换为可空类型:

    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;
    }
public static Nullable ConvertToNullable(此字符串为s),其中T:struct
{
如果(!string.IsNullOrEmpty(s.Trim()))
{
TypeConverter conv=TypeDescriptor.GetConverter(typeof(null).MakeGenericType(typeof(T));
返回(可为空)conv.ConvertFrom;
}
返回null;
}
公共静态T To(此IConvertible obj)
{
类型t=类型(t);
if(t.IsGenericType&&t.GetGenericTypeDefinition()==typeof(可为空))
t=t.GetGenericArguments()[0];
返回(T)转换.ChangeType(obj,T);
}
但是,如果转换失败,它将抛出异常,而不会像预期的那样返回null。

公共静态T To(此IConvertible obj)
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);
    }
}
{ 类型t=类型(t); 类型u=可空。GetUnderlineType(t); 如果(u!=null) { 返回值(obj==null)?默认值(T):(T)Convert.ChangeType(obj,u); } 其他的 { 返回(T)转换.ChangeType(obj,T); } }
卢克的解决方案对我来说是好的(而且显然得到了他的支持),但我用这种方式简化了它

    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;
    }
因为我是从字符串开始的,而不是从类型开始的。。。
想法?

我的结局是这样的

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); }
private static T To(this Object@Object,Boolean returnDefaultOnException)
{
类型=类型(T);
类型UnderlyngTypeOfNullable=Nullable.GetUnderlyngType(类型);
尝试
{
return(T)Convert.ChangeType(@object,underyingTypeOfNullable??type);
}
捕获(异常)
{
if(returnDefaultOneException)
返回默认值(T);
字符串typeName=type.Name;
if(underlineTypeOfNullable!=null)
typeName+=“+UnderlineTypeOfNullable.Name”中的“+”;
抛出新的InvalidCastException(“对象不能转换为”+typeName,exception);
}
}
公共静态T To(this Object@Object){return@Object.To(returnDefaultOneException:false);}
公共静态T ToOrDefault(this Object@Object){return@Object.To(returnDefaultOneException:true);}
它的行为类似于LINQ扩展方法
Single
SingleOrDefault
First
FirstOrDefault

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

extend@LukeH code:

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);
        }
    }
publicstatict GetValue(字符串文本,T DefaultValue)
{
if(Literal==null | | Literal==“”| | Literal==string.Empty)返回DefaultValue;
IConvertible obj=文字;
类型t=类型(t);
类型u=可空。GetUnderlineType(t);
如果(u!=null)
{
return(obj==null)?DefaultValue:(T)Convert.ChangeType(obj,u);
}
其他的
{
返回(T)转换.ChangeType(obj,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;
    }
//
///比使用T.TryParse(string,out T)更方便。
///使用基元类型、结构和枚举。
///尝试将字符串解析为指定类型的实例。
///如果无法解析输入,将返回null。
/// 
/// 
///如果调用方的值为null,则返回null。
///因此,如果您有“string s=null;”,然后尝试“s.ToNullable…”,
///将返回null。不会引发空异常。
/// 

///

请参阅我的问题:是否有办法将其应用到我现有的方法中,并让它检测可为空的泛型,并进行适当的处理?您可以这样说。。。if(typeof(T).IsGeneric&&typeof(T).GetGenericTypeDefinition().Name.StartsWith(“Nullable”))将告诉您该类型是否可为null。然后可以应用这个特殊情况,但我不确定当接受非结构类型时,它是否可以工作。如果您想要更改为使用Tonulable,会有什么问题?谢谢Luke!这太完美了。在这里真正帮助我的是t.GetGenericTypeDefinition()==typeof(Nullable))和Nullable.GetUnderlyingType(t)。这是好东西。再次感谢。根据您的需要,将if(obj==null)更改为if(obj==null | | obj是String&&obj.ToString()==“”)会很有帮助,作为一个小小的简化/澄清,如果T是可空的,obj是null,那么
返回默认值(T)
是否总是与简单地
返回null
相同?@goodeye:是的,这是sam
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); }
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);
        }
    }
    /// <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;
    }