[解決済み] なぜrefとoutはポリモーフィズムをサポートしないのですか?
疑問点
次のように考えてください。
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) {}
}
上記のコンパイル時エラーはなぜ発生するのでしょうか?このエラーは
ref
と
out
という引数があります。
どのように解決するのですか?
=============
UPDATE: このブログエントリーのベースとなる回答として、この回答を使用しました。
refとoutのパラメータはなぜ型の変化を許さないのですか?
この問題についての解説は、ブログページをご覧ください。 素晴らしい質問をありがとうございました。
=============
例えば、以下のようなクラスがあるとします。
Animal
,
Mammal
,
Reptile
,
Giraffe
,
Turtle
と
Tiger
であり、明らかなサブクラス化の関係を持っています。
ここで、あるメソッド
void M(ref Mammal m)
.
M
は読み書きの両方が可能です
m
.
型変数を渡すことはできますか?
Animal
をM
?
いいえ、その変数には
Turtle
が、しかし
M
は哺乳類だけを含むと仮定します。A
Turtle
は
Mammal
.
結論 1
:
ref
パラメータはquot;big"にできない(哺乳類より動物の方が多いので、変数に入れられるものが増えてquot;big"になっている)。
型変数を渡すことはできますか?
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における共分散と共分散の動作に関する私のシリーズを読んでみてください。 .
関連
-
[解決済み】ファイルへの読み書きの際に共有違反のIOExceptionが発生する C#
-
[解決済み】2つ(またはそれ以上)のリストを1つに統合する(C# .NETで
-
[解決済み] プロパティまたはインデクサは、outまたはrefパラメータとして渡すことはできません。
-
[解決済み] なぜList<T>を継承しないのですか?
-
[解決済み] キーワード「ref」と「out」の違いは何ですか?
-
[解決済み] ポリモーフィズムとは何か、何のためにあり、どのように使われるのか?
-
[解決済み] テンプレート型のC#ジェネリックnew()への引数の渡し方
-
[解決済み] なぜ「public static const string S = "stuff";」をクラスで使用できないのでしょうか?
-
[解決済み] C#で演算子==はジェネリック型に適用できない?
-
[解決済み] ラムダ式でrefやoutパラメータを使用できない
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】エラー。「戻り値を変更できません」 C#
-
[解決済み】WebForms UnobtrusiveValidationModeは、jqueryのScriptResourceMappingを必要とする
-
[解決済み】SmtpException: トランスポート接続からデータを読み取れません:net_io_connectionclosed
-
[解決済み】リソースの読み込みに失敗した:ステータス500(内部サーバーエラー)のサーバーの応答)
-
[解決済み】値が期待した範囲に収まらない
-
[解決済み】C# - パスに不正な文字がある場合
-
[解決済み] 'IEnumerable<SelectListItem>' 型の ViewData アイテムで、キーが国であるものは存在しない。
-
[解決済み】MetadataException: 指定されたメタデータ・リソースをロードできない
-
[解決済み】HRESULTからの例外:0x800A03ECエラー
-
[解決済み】プロセスが実行されているかどうかを知るには?