2011-01-25 7 views
2

なぜEnumerable.Cast <>は変換演算子を使用しませんか?このタイプの使用

var ok=test.Select(x => (int)x).ToList(); 

が、キャスト<を使用して期待通り

class Foo 
{ 
    public static implicit operator int(Foo obj) 
    { 
    return 5; 
    } 
} 

var test=new[] { new Foo() }; 

次の作品は> InvalidCastExceptionがで失敗する - なぜですか?

var fail=test.Cast<int>().ToList(); 
+1

これがあなたの問題であるかどうかを確認してください:http://stackoverflow.com/questions/445471/puzzling-enumerable-cast-invalidcastexception/445497#445497 –

+0

私はこれを試しましたが、あなたのコード例はまったく動作しませんでした。 InvalidCastExceptionを伴う行、この例がうまくいきますか? –

+0

@matt - はい、リンクありがとうございます!以前はそれを見ていなかった。 – laktak

答えて

2

Linq(EduLinq)、具体的にはpart 33を再実装することに関するJon Skeetのブログを読んでください。ここで彼はどこにいるのですか?

キャストとOfTypeは参照とアンボックスの変換のみを実行します(.NET 3.5 SP1以降)。 boxed intをlong型に変換したり、ユーザー定義の変換を実行したりすることはありません。基本的には、オブジェクトからジェネリック型パラメータへの変換と同じ規則に従います。

0

Enumerable.Castのドキュメントは、実際にはあまりにも曖昧で、キャストと変換に関する話です。しかし、 "要素がTResult型にキャストできない場合、このメソッドは例外をスローします"、クラスFooはintにキャストできませんが、キャスト構文を使用して変換できます。後者はメソッド呼び出しです。

通常キャストと「で」「として」OfTypeがに似仕事とあなたが書いた場合:

var foo = new Foo() 
var bar = foo is int; 

バーがfalseになります。 Castはそれと一貫しているように見えます(ただし、MSDNのドキュメントは完全ではありません)。 is演算子がfalseを返すと失敗します。

1

キャスト演算子は純粋にC#コンパイラレベルの機能であり、実行時には何も知らないため、汎用キャストメソッドを使用してこれを実装する簡単な方法はありません。これを行う1つの方法は、実行時のコード生成を実行することです:

 

    public static class Converter<TSource, TResult> 
    { 
     static Converter() 
     { 
      var sourceParameter = Expression.Parameter(typeof(TSource)); 
      var conversionExpression = Expression.Lambda<Func<TSource, TResult>>(
       Expression.Convert(sourceParameter, typeof(TResult)), 
       sourceParameter); 

      Instance = conversionExpression.Compile(); 
     } 

     public static Func<TSource, TResult> Instance 
     { 
      get; 
      private set; 
     } 
    } 

    public static class EnumerableEx 
    { 
     public static IEnumerable<TResult> Cast<TSource, TResult>(this IEnumerable<TSource> source) 
     { 
      return source.Select(Converter<TSource, TResult>.Instance); 
     } 
    } 
 

が、その後、あなたはコンパイル時にチェックを失うでしょう:もう一つの方法はPuzzling Enumerable.Cast InvalidCastExceptionのようにリフレクションを使用することですが、この

 

var test = new[] { new Foo() }; 
var ok = test.Cast<Foo, int>().ToList(); // compiles and works ok 
var error = test.Cast<Foo, double>().ToList(); // compiles but fails at run-time 
 

をintからlongへのような組み込みの変換では機能しません。

関連する問題