无法在泛型方法中将类型更改为可为空
Posted
技术标签:
【中文标题】无法在泛型方法中将类型更改为可为空【英文标题】:Cannot change type to nullable in generic method 【发布时间】:2012-05-06 07:05:11 【问题描述】:我正在创建一个通用转换器
这是通用转换器的示例代码
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。
edit 问题是StringToNullableDatetime
方法返回一个Datetime?
并且强制转换说不能从Datetime
转换
既然StringToNullableDatetime
方法返回一个可以为空的日期时间,那Convert.ChangeType
怎么可能看不到传递的参数可以为空呢?
附言。我读过类似this 的答案,相反的答案(从可空值转换)。
【问题讨论】:
【参考方案1】:抛出的异常表示它无法从
DateTime
转换为Nullable<DateTime>
。既然方法创建并返回了一个可以为空的类型,那么为什么转换会失败呢?
好问题。这失败了,因为不存在盒装可为空的东西。当您将DateTime?
转换为object
时,如果DateTime?
为空,您将获得一个空引用,或者您将获得一个装箱的值,即DateTime
。你永远不会得到一个盒装的可为空结构;没有这样的东西。
因此,您最终会在该框中得到 null 或有效的 DateTime。然后,您告诉 Convert 将其转换为可为空的 DateTime,而 Convert 不知道该怎么做。
我的建议是你完全放弃这条攻击线;这段代码是对泛型的滥用。每当您切换特定类型的泛型时,您的代码就不再是 generic 并且您可能做错了。如果你想为日期时间做一个“尝试”风格的方法,那么只需写下:
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) ...
【讨论】:
【参考方案2】:来自documentation,如果出现以下情况,此行将出错:
value 为 null,conversionType 为值类型
Nullable<T>
是一个结构体,因此是一个值类型,因此如果您的值为 null,则不能使用此方法调用。您已经单独处理日期,那么为什么还要在这些情况下使用ChangeType
?
【讨论】:
编辑了我的问题。我的问题是我无法返回 Nullable 日期时间。Convert.ChangeType
行看不到传递的参数可以为空【参考方案3】:
可空值、泛型和装箱的交互方式很奇怪。您最好定义两种方法:
bool TryReaderParse(object data, out TType value); bool TryReaderParse(object data, out TType? value) where TType : struct;在第二种方法中,您的代码可以简单地生成TType
并将其分配给TType?
毫无困难。
【讨论】:
首先,一个方法不能仅在约束上重载。其次,如果该方法返回一个可为空的值,那么为什么它还需要返回一个布尔值?如果您要这样做,那么正确的签名是T TryParseClass<T>(object data) where T : class
和T? TryParseStruct<T>(object data) where T : struct
。不需要布尔值。以上是关于无法在泛型方法中将类型更改为可为空的主要内容,如果未能解决你的问题,请参考以下文章