4

インターフェイス型からジェネリック構造体型にユーザー定義のキャスト演算子を使用しようとすると、型を変換できないことを示すコンパイルエラーが発生します。

public interface J { }
public struct S<T> {
    public static explicit operator S<T>(T value) {
        return new S<T>();
    }
}
public static class C {
    public static S<J> Test(J j) {
        return (S<J>)j; // <- error: cannot convert type 'J' to type 'S<J>'
    }
}

Jがクラスの場合、変換は機能することに注意してください。

クラスへの変換についても同様の質問があります。その答えは、派生クラスがインターフェイスを実装し、ユーザー定義のキャストを使用する必要があるかどうかについてあいまいさを生み出す可能性があるということです。しかし、構造体の場合、派生型は存在できず、コンパイラーは、私の構造体がJを実装していないことを認識しています。

おそらく、インターフェースが新しいインターフェースを実装するときに、予期しないセマンティックの変更を回避するためですか?多分それはただの偶然ですか?多分私は素朴な間違いを犯していますか?スペックからの引用は素晴らしいのですが、そもそもそのように設計された理由が本当に欲しいです。

4

1 に答える 1

6

を実装していないため、システムは実際のキャストを実行できません。宣言を変更すると、正常に機能します。S<J>J

public struct S<T> : J {...}

クラスの場合、を実装するクラスのサブタイプを宣言することができJます。ただし、構造体を拡張することはできないため、S実装しない場合は、「 isa J」であるクラスも実装されないことを保証できます。したがって、はありません。SJJS<T>

では、なぜ明示的なキャスト演算子を呼び出さないのでしょうか。このSOの投稿で説明されているように、答えはC#仕様にあると思います。


6.4.1許可されたユーザー定義の変換

C#では、特定のユーザー定義の変換のみを宣言できます。特に、既存の暗黙的または明示的な変換を再定義することはできません。特定のソースタイプSおよびターゲットタイプTについて、SまたはTがnull許容型である場合は、S0およびT0がそれらの基になる型を参照するようにします。そうでない場合、S0およびT0はそれぞれSおよびTに等しくなります。クラスまたは構造体は、次のすべてが当てはまる場合にのみ、ソースタイプSからターゲットタイプTへの変換を宣言できます。

  • S0とT0は異なるタイプです。
  • S0またはT0は、演算子宣言が行われるクラスまたは構造体タイプです。
  • S0もT0もインターフェイスタイプではありません
  • ユーザー定義の変換を除いて、SからTへの変換またはTからSへの変換は存在しません。

したがって、私がその権利を読んでいる場合、Jはインターフェイスであるため、明示的なキャスト演算子の候補として認識されません。

于 2012-10-05T19:09:37.543 に答える