我正在创建一个通用转换器
以下是通用转换器的示例代码
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这样的答案,这些答案正好相反(从可空中铸造)。
答案 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?
。