在泛型方法中无法将类型更改为可为空

时间:2012-04-25 15:01:00

标签: c# generics .net-3.5 casting nullable

我正在创建一个通用转换器

以下是通用转换器的示例代码

bool TryReaderParse<TType>(object data, out TType value)
{
    value = default(TType);
    Type returnType = typeof(TType);
    object tmpValue = null;

    if (returnType == typeof(DateTime))
    {
        tmpValue = StringToDatetime(data.ToString());
    }
    else if (returnType == typeof(DateTime?)) // THIS IF FIRES
    {
        tmpValue = StringToNullableDatetime(data.ToString());
    }

    value = (TType)Convert.ChangeType(tmpValue, returnType);  // THROWS
}

public DateTime? StringToNullableDatetime(string date)
{
    DateTime? datetime = null;
    if (!string.IsNullOrEmpty(date))
    {
        datetime = DateTime.Parse(date, new CultureInfo(Resources.CurrentCulture));
    }

    return datetime;
}

这就是我使用它的方式:

void foo()
{
    DateTime? date = null;
    TryReaderParse<DateTime?>("25/12/2012", out date);
}

抛出的异常表示无法从DateTime转换为Nullable<DateTime>。既然,该方法创建并返回一个可空类型,那么转换如何失败?

最后,我希望在这个特定的例子中有一个可以为空的DateTime。

修改问题是,StringToNullableDatetime方法会返回Datetime?,而投射说不能转换为Datetime

由于StringToNullableDatetime方法返回可为空的日期时间,Convert.ChangeType怎么可能看不到传递的参数可以为空?

聚苯乙烯。我已经阅读了像this这样的答案,这些答案正好相反(从可空中铸造)。

3 个答案:

答案 0 :(得分:18)

  

抛出的异常表示无法从DateTime转换为Nullable<DateTime>。既然,该方法创建并返回一个可空类型,那么转换如何失败?

好问题。这失败了,因为没有盒装可空的这样的东西。当您将DateTime?转换为object时,您可以获得空引用,如果DateTime?为空,或者您获得了装箱,则为{{ 1}}。你永远不会得到一个盒装的可空结构;没有这样的事情。

因此,您最终会使用null或该框中的有效DateTime。然后告诉Convert将其转换为可以为空的DateTime,并且Convert不知道如何做到这一点。

我的建议是你完全抛弃这一攻击线;这段代码是泛滥的泛型。无论何时切换特定类型的泛型,您的代码都不再是泛型,而您可能做错了。如果你想为日期时间做一个“尝试”式的方法,那就写下:

DateTime

打算读取的每个类型编写这样的方法。用户更愿意写:

DateTime? TryReadDateTime(object data)
{
    ... return null if the object cannot be read as a datetime ...
}

DateTime? d = TryReadDateTime(data);
if (d != null) ...

答案 1 :(得分:0)

documentation开始,如果符合以下条件,则此行会出错:

  

value为null,conversionType为值类型

Nullable<T>是一个结构,因此是一个值类型,因此如果您的值为null,则不能使用此方法调用。您已经单独处理日期,那么为什么在这些情况下使用ChangeType呢?

答案 2 :(得分:0)

nullables,generics和boxing相互作用的方式很奇怪。你可能最好定义两种方法:

bool TryReaderParse(object data, out TType value);
bool TryReaderParse(object data, out TType? value) where TType : struct;

在第二种方法中,您的代码可以简单地生成TType并毫无困难地将其分配给TType?