=============
更新:私はこの回答をこのブログエントリの基礎として使用しました。
refおよびoutパラメータで型のバリエーションが許可されないのはなぜですか?
この問題の詳細については、ブログページを参照してください。すばらしい質問をありがとう。
=============
あなたがクラスを持っているとしましょうAnimal
、Mammal
、Reptile
、Giraffe
、Turtle
およびTiger
、明白なサブクラスの関係を持ちます。
次に、メソッドがあるとしますvoid M(ref Mammal m)
。 M
読み取りと書き込みの両方ができますm
。
あなたは、型の変数を渡すことができますAnimal
にM
?
いいえ。その変数にはを含めることができますがTurtle
、M
哺乳類のみが含まれていると想定されます。A Turtle
はではありませんMammal
。
結論1:ref
パラメータを「大きく」することはできません。(哺乳類よりも動物の方が多いため、より多くのものを含むことができるため、変数は「大きく」なります。)
あなたは、型の変数を渡すことができますGiraffe
にM
?
いいえM
に書き込むことができm
、そしてM
書きたいかもしれないTiger
にしm
。Tiger
これで、実際に型である変数にを入れましたGiraffe
。
結論2:ref
パラメータを「小さく」することはできません。
今考えなさいN(out Mammal n)
。
あなたは、型の変数を渡すことができますGiraffe
にN
?
いいえN
に書き込むことができn
、そしてN
書きたいかもしれませんTiger
。
結論3:out
パラメータを「小さく」することはできません。
あなたは、型の変数を渡すことができますAnimal
にN
?
うーん。
さて、なぜですか? N
から読み取ることはできません。n
書き込むことしかできません。Tiger
型の変数にを書き込んで、Animal
すべて設定しましたよね?
違う。ルールは「N
書き込みのみ可能」ではありませんn
。
ルールは、簡単に言えば:
1)正常に戻る前N
に書き込む必要があります。(スローした場合、すべてのベットはオフになります。)n
N
N
2)N
が何かをn
読み取る前に、何かに書き込む必要がありますn
。
これにより、この一連のイベントが可能になります。
x
型のフィールドを宣言しますAnimal
。
- パラメータ
x
としてに渡しout
ますN
。
N
書き込みTiger
へn
の別名です、x
。
- 別のスレッドでは、誰かが書き込みを行う
Turtle
にはx
。
N
はの内容を読み取ろうとし、型の変数であると考えているものn
を見つけTurtle
ますMammal
。
明らかにそれを違法にしたいのです。
結論4:out
パラメータを「大きく」することはできません。
最終的な結論:どちらのパラメータもタイプを変えることはできませref
んout
。そうでなければ、検証可能な型安全性を破ることになります。
基本的な型理論のこれらの問題に興味がある場合は、C#4.0での共分散と反変がどのように機能するかについての私のシリーズを読むことを検討してください。