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

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

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

bool TryReaderParse(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("25/12/2012", out date); } 

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

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

编辑问题是StringToNullableDatetime方法返回一个Datetime? 并且铸造说无法从Datetime转换

由于StringToNullableDatetime方法返回可为空的日期时间,因此Convert.ChangeType如何才能看到传递的参数可以为空?

PS。 我已经读过像这样的答案, 这些答案正好相反(从可空中铸造)。

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

好问题。 这失败了,因为没有盒装可空的东西 。 转换DateTime? object ,你要么得到一个空引用,如果DateTime? 为null,或者您获得了盒装 ,即DateTime 。 你永远不会得到一个盒装的可空结构; 哪有这回事。

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

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

 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(data, out d); if (b) ... 

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

value为null,conversionType是值类型

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

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

 bool TryReaderParse(对象数据,输出TType值);
 bool TryReaderParse(对象数据,输出TType?value)其中TType:struct;

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