1. ホーム
  2. c#

[解決済み] なぜrefとoutはポリモーフィズムをサポートしないのですか?

2022-07-22 12:55:18

疑問点

次のように考えてください。

class A {}

class B : A {}

class C
{
    C()
    {
        var b = new B();
        Foo(b);
        Foo2(ref b); // <= compile-time error: 
                     // "The 'ref' argument doesn't match the parameter type"
    }

    void Foo(A a) {}

    void Foo2(ref A a) {}  
}

上記のコンパイル時エラーはなぜ発生するのでしょうか?このエラーは refout という引数があります。

どのように解決するのですか?

=============

UPDATE: このブログエントリーのベースとなる回答として、この回答を使用しました。

refとoutのパラメータはなぜ型の変化を許さないのですか?

この問題についての解説は、ブログページをご覧ください。 素晴らしい質問をありがとうございました。

=============

例えば、以下のようなクラスがあるとします。 Animal , Mammal , Reptile , Giraffe , TurtleTiger であり、明らかなサブクラス化の関係を持っています。

ここで、あるメソッド void M(ref Mammal m) . M は読み書きの両方が可能です m .


型変数を渡すことはできますか? AnimalM ?

いいえ、その変数には Turtle が、しかし M は哺乳類だけを含むと仮定します。A TurtleMammal .

結論 1 : ref パラメータはquot;big"にできない(哺乳類より動物の方が多いので、変数に入れられるものが増えてquot;big"になっている)。


型変数を渡すことはできますか? GiraffeM ?

いいえ。 M に書き込むことができます。 m であり、かつ M を書きたいかもしれません。 Tigerm . これで Tiger を変数に入れましたが、これは実際には Giraffe .

結論2 : ref パラメータを小さくすることはできません。


次に N(out Mammal n) .

型の変数を渡すことができますか? GiraffeN ?

いいえ。 N に書き込むことができます。 n であり、かつ N を書きたいかもしれません。 Tiger .

まとめ3 : out パラメータを小さくすることはできません。


型変数を渡すことはできますか? AnimalN ?

ふむ。

まあ、いいんじゃない? N から読み取ることはできません。 n から読み取ることはできず、書き込むことしかできないのですね? あなたは Tiger 型の変数に Animal を追加すれば、準備は完了ですね?

間違っています。ルールは"ではありません。 N にしか書き込めません。 n にしか書き込めません。

ルールは、簡単に言うと

1) N に書き込まなければなりません。 n の前に N は正常に戻ります。(もし N が投げられたら万事休すです)。

2) N には何かを書き込まなければなりません。 n から何かを読み込む前に n .

それがこの一連の流れを許すのです。

  • フィールドを宣言する x 型の Animal .
  • パス xout のパラメータとして N .
  • N を書き込みます。 Tigern のエイリアスである x .
  • 別のスレッドで、誰かが Turtlex .
  • N の内容を読み取ろうとします。 n の内容を読もうとすると Turtle 型の変数と思われるものに Mammal .

明らかに違法にしたい。

結論 4 : out パラメータを大きくすることはできません。


最終結論 : どちらでもない refout パラメーターはその型を変えることができます。そうでなければ、検証可能な型安全性を破ることになります。

もしあなたが基本的な型理論のこれらの問題に興味があるなら、以下を読むことを検討してください。 C# 4.0における共分散と共分散の動作に関する私のシリーズを読んでみてください。 .