2010-05-12 83 views
16

對一些LINQ之間的轉換成SQL對象,我們對創建的DTO顯式類型轉換操作符的DTO。這樣我們可以做到以下幾點:LINQ .Cast()擴展方法失敗,但(型)對象的工作

DTOType MyDTO = (LinqToSQLType)MyLinq2SQLObj; 

這很好。

但是當您嘗試使用LINQ .Cast()擴展方法來投它trows無效轉換異常說不能投類型Linq2SQLType鍵入DTOType。即低於不起作用

List<DTO.Name> Names = dbContact.tNames.Cast<DTO.Name>() 
               .ToList(); 

但低於正常工作:

DAL.tName MyDalName = new DAL.tName(); 
DTO.Name MyDTOName = (DTO.Name)MyDalName; 

及以下也能正常工作

List<DTO.Name> Names = dbContact.tNames.Select(name => (DTO.Name)name) 
               .ToList(); 

爲什麼.Cast()擴展方法拋出無效的轉換異常?過去我多次用這種方法使用.Cast()擴展方法,並且當您將類似於基本類型的東西轉換爲派生類型時,它可以很好地工作,但在對象具有明確的轉換運算符時會下降。

+0

可能重複的[Puzzling Enumerable.Cast InvalidCastException](http://stackoverflow.com/questions/445471/puzzling-enumerable-cast-invalidcastexception) – 2010-05-12 14:15:06

回答

21

Cast<>擴展方法不適用戶定義的轉換。它只能轉換爲接口或所提供類型的類級別。

用戶定義的轉換是在基於參與表達的靜態類型編譯時間標識。它們不能被用作運行時轉換,因此下面是非法的:

public class SomeType 
{ 
    public static implicit operator OtherType(SomeType s) 
    { 
    return new OtherType(); 
    } 
} 

public class OtherType { } 

object x = new SomeType(); 
OtherType y = (OtherType)x; // will fail at runtime 

不要緊,一UDC無論從SomeTypeOtherType存在 - 它無法通過object型的參考應用。試圖運行上面的代碼會在運行時失敗,報告是這樣的:

System.InvalidCastException: 
    Unable to cast object of type 'SomeType' to type 'OtherType' 

Cast<>()只能執行表示保留轉換......這就是爲什麼你不能用它來應用用戶定義的轉換。

埃裏克利珀有大約behavior of the cast operator in C#一個偉大的文章 - 永遠是值得讀。

+0

我確實在我的問題中說,我已經觀察到你通過descibe的行爲經驗,我問的是爲什麼它不適用於用戶定義的轉換。它有什麼不同,它不適用於明確的演員操作,它如何演員? – 2010-05-12 14:10:02

+0

Ben:當你寫評論時,我正在詳細闡述我的答案:)讓我知道這是否清楚了爲什麼'Cast <>()'按照它的方式工作。 – LBushkin 2010-05-12 14:15:02

+0

好的,是的,這是有道理的謝謝,我做了一些挖掘與反射器,這是幾乎無法解讀,但它暗示你的解釋,謝謝。 – 2010-05-12 14:26:46

2

如果你反編譯Linq程序集,你會得到類似下面的代碼。以前的答案是正確的,最終演員是從'對象'到目標類型,這對於自定義類型來說總是失敗。

private static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source) 
{ 
    foreach(object current in source) 
    { 
     yield return (TResult)((object)current); 
    } 
    yield break; 
} 

public static IEnumerable<TResult> DCast<TResult>(this IEnumerable source) 
{ 
    IEnumerable<TResult> enumerable = source as IEnumerable<TResult>; 
    if(enumerable != null) 
    { 
     return enumerable; 
    } 
    if(source == null) 
    { 
     throw new ArgumentNullException("source"); 
    } 
    return CastIterator<TResult>(source); 
} 

TFish

+0

感謝您的輸入,但我明白了原來的答案。 – 2013-08-29 06:39:53

0

對於那些打這個問題尋找解決方法...

Dim res = arrayOfStrings.Select(Function(__) CType(__, YourType)) 

不知道用C#的精確語義,但我敢肯定,這是很容易。