5

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

这是通用转换器的示例代码

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

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

最后,在这个特定的示例中,我想要一个可为空的 DateTime。

编辑问题是StringToNullableDatetime方法返回 aDatetime?并且强制转换说不能从Datetime

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

附言。我读过这样一个相反的答案(从可为空的转换)。

4

3 回答 3

18

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

好问题。这失败了,因为没有装箱的 nullable 之类的东西。当您将 a 转换为DateTime?object,您将获得一个空引用(如果 aDateTime?为 null),或者您获得装箱a DateTime。你永远不会得到一个盒装的可空结构;哪有这回事。

因此,您最终会在该框中获得 null 或有效的 DateTime。然后,您告诉 Convert 将其转换为可为空的 DateTime,而 Convert 不知道该怎么做。

我的建议是你完全放弃这条攻击线;这段代码是对泛型的滥用。任何时候你对泛型的特定类型进行切换,你的代码就不再是泛型的,你可能做错了。如果你想为日期时间做一个“尝试”风格的方法,那么只需写下:

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

为您打算阅读的每种类型编写这样的方法。用户更愿意写:

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

DateTime d;
bool b = TryRead<DateTime>(data, out d);
if (b) ...
于 2012-04-25T15:23:48.950 回答
0

文档中,如果出现以下情况,此行将出错:

value 为 null,conversionType 为值类型

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

于 2012-04-25T15:05:31.660 回答
0

可空值、泛型和装箱交互的方式很奇怪。您最好定义两种方法:

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

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

于 2012-04-25T15:20:20.497 回答