在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?
没有困难。