2012-04-25 112 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