2012-04-25 109 views
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); 
} 

引发的异常说明它无法从DateTime转换为Nullable<DateTime>。既然,该方法创建并返回一个可为空的类型,那么该投射如何失败?

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

编辑的问题是,StringToNullableDatetime方法返回一个Datetime?和铸造说,不能从Datetime

转换由于StringToNullableDatetime方法返回一个可为空的日期时间,它怎么可能是Convert.ChangeType无法看到通过论点是可空的?

Ps。我已经阅读了this这样的答案,可以做相反的事情(从可空值转换)。

值为null和conversionType是值类型

Nullable<T>是一个结构,因此值类型,因而不能:

回答

18

抛出的异常说明它无法从DateTime转换为Nullable<DateTime>。既然,该方法创建并返回一个可为空的类型,那么该投射如何失败?

好问题。这失败了,因为没有像盒装空值那样的东西。当您将DateTime?转换为object时,如果DateTime?为空,或者您获得盒装,则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) ... 
0

documentation,如果此线将出错如果您的值为空,请使用此方法调用。您已经分别处理日期,那么为什么在这些情况下使用ChangeType

+0

编辑我的问题。我的问题是我不能返回一个可空的日期时间。 'Convert.ChangeType'行看不到传递的参数是可空的 – Odys 2012-04-25 15:20:24

0

空方式,泛型和拳击相互作用的方式很奇怪。你可能会更好定义了两种方法:

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

在第二种方法,你的代码可以直接产生TType,并将其分配给TType?没有困难。

+2

首先,一个方法可能不会仅限制在约束上。其次,如果方法返回一个可为空的值,那么*为什么它也需要返回一个bool *?如果你打算这样做,那么正确的签名是'T TryParseClass (对象数据),其中T:class'和'T? TryParseStruct (object data)where T:struct'。没有必要的布尔。 – 2012-04-25 15:27:31