18

重複投票を決定する前に、最後までお読みください...

implicit cast別のタイプに演算子を実装するタイプがあります。

class A
{
    private B b;
    public static implicit operator B(A a) { return a.b; }
}
class B
{
}

これで、暗黙的および明示的なキャストは問題なく機能します。

B b = a;
B b2 = (B)a;

...では、なぜLinqはそうで.Cast<>はないのですか?

A[] aa = new A[]{...};
var bb = aa.Cast<B>();  //throws InvalidCastException

のソースコードを見ると、.Cast<>あまり魔法がかかっていません。パラメータが実際にである場合のいくつかの特殊なケースIEnumerable<B>、そして次のようになります。

foreach (object obj in source) 
    yield return (T)obj; 
    //            ^^ this looks quite similar to the above B b2 = (B)a;

では、なぜ私の明示的なキャストは機能するのに、内部のキャストは機能しないの.Cast<>ですか?

コンパイラは私の明示的なキャストをシュガーアップしますか?

PS。私はこの質問を見ましたが、その答えが実際に何が起こっているのかを説明しているとは思いません。

4

3 に答える 3

16

では、なぜ私の明示的なキャストが機能し、.Cast <>内のキャストが機能しないのですか?

明示的なキャストは、コンパイル時にソースと宛先のタイプが何であるかを知っています。コンパイラーは、明示的な変換を見つけて、それを呼び出すためのコードを発行できます。

ジェネリック型の場合はそうではありません。これはLINQに固有のものではないことに注意してください。簡単な方法Castを試した場合も、同じことがわかります。Convert

public static TTarget Convert<TSource, TTarget>(TSource value)
{
    return (TTarget) value;
}

これにより、ユーザー定義の変換は呼び出されませint。また、(たとえば)からへの変換も呼び出されませんlong。参照変換とボクシング/アンボクシング変換のみを実行します。これは、ジェネリックスの仕組みの一部にすぎません。

于 2013-01-25T14:14:59.127 に答える
11

簡単に言うと、このCast<T>メソッドはカスタム変換演算子をサポートしていません。

最初の例では:

B b = a;
B b2 = (B)a;

B(A a)コンパイラーは静的分析中にこの演算子を見ることができます。callコンパイラは、これをカスタム演算子メソッドに対する静的なものとして解釈します。2番目の例では:

foreach (object obj in source) 
    yield return (T)obj; 

オペレーターの知識がありません。これは( ref-typeの場合とunbox.any同じ)を介して実装されます。castclassT

3番目のオプションもあります。を経由しdynamicた場合、ランタイム実装はコンパイラルールを模倣しようとするため、演算子見つかります...ただし、C#からILへのコンパイル手順の一部としてではありません。

dynamic b = a; // note that `dynamic` here is *almost* the same as `object`
B b2 = b;
于 2013-01-25T14:19:22.103 に答える
3

Enumerable.Cast<T>は.NetFrameworkメソッドであり、それを呼び出すすべての.Net言語で意味のある動作をします。

この議論に関するAnderHejlsbergの回答も参照してください。


コンパイラは私の明示的なキャストをシュガーアップしますか?

「暗黙のキャスト演算子」と呼ばれるものは、実際には「暗黙の変換演算子」です。よくある間違いです。

C#では、キャスト構文を使用して変換を指定できます。これが発生した場合、同じインスタンスへの参照を変更する(キャストする)のではなく、別のインスタンスを使用する(変換する)ことになります。

于 2013-01-25T14:54:31.880 に答える