16
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【C#】メソッドのオーバライド、返値型を元の型の派生型にできない。【covariant return types】

Last updated at Posted at 2018-12-05

追記 : C# 9.0では、covariant return typesが追加されるようです。


2018年現在のC#(C# 7.3とかそれより前)では、オーバライド元のメソッドとオーバライドしたメソッドで、返値型は同じ型にしないといけない。そのため、メソッドをオーバーライドした時、返値型を派生型にできない。

ちなみに、これJavaだとできる。「共変戻り値型って知ってますか?(スライド)

どう困るのか

「そんなん別にできなくてもよくない?」
「え、できなかったんだ?でも、気づかなかったんだから、大した問題じゃないんじゃ?」
「知ってた。別に困らなくないか?」

そう思う人も多いかもしれないけれど、これができないから次みたいな例で困る・・・。

public class Enemy
{
    /* 略 */
}

public class BossEnemy : Enemy
{
    /* 略 */
}

public class EnemyFactory
{
    public virtual Enemy Create() { return new Enemy(); }
}

public class BossEnemyFactory : EnemyFactory
{
    // ↓こう書きたい。けれどコンパイルエラーになってしまう
    // BossEnemyFactoryを使う際はこう書けた方が便利なことがある
    // public override BossEnemy Create () { return new BossEnemy(); }

    // 実際は、BossEnemy型のインスタンスしか返さない
    // ↓こう書くしかない。
    public override Enemy Create() { return new BossEnemy(); }
}

「メソッドをオーバライドする際、その返値型を元のメソッドの返値型の派生型にできない」

だから、BossEnemyFactory型のCreateメソッドは、返値型はEnemyにするしかない。

もし返値型をBossEnemyにできると、便利な場面がある。

(ちなみにメソッドの返値型はEnemyだけど、インスタンス自体はBossEnemy型にはもちろんできる。)

言語仕様に書いてある

これはC#の仕様。

C#的に、

The override method and the overridden base method have the same return type.

らしい。

将来的にはできるようになる可能性も

で、これ将来的にはできるようになるかもしれない。

(かもしれないってだけど、まだ残念ながら可能性。)

dotnet/csharplangリポジトリのマイルストーンには、「7.0」、「8.X candidate」などのマイルストーンに並んで、「X.0 candidate」というマイルストーンがある。このマイルストーンは、

These candidate features could be included in any major or minor release.

とのことで、このマイルストーンに入っているissueは、いつかのメジャーバージョンで機能として入るかもしれない。

そこに、この「メソッドをオーバーライドした時、返値型を派生型にできるようにする」という「covariant return types」が上がっている。

で今の所、プロポーザルがある。加えて、こんないろいろ検証したプロポザールのプルリクエスも最近上がったみたい・・・

いろいろ優先順位とか、他への悪影響とかあるかもしれないから、できるかどうかはわからないけれど・・・。もしかしたら、将来的にはできるようになるかも。

ちなみに、Issueではこんな会話もあった。

Seriously, there are a million "good" ideas, modifying the language is a very expensive process and the team has finite resources. Things take time.

正しい。めっちゃ正しい。

まとめ

C#の仕様的に、

「メソッドをオーバライドする際、その返値型を元のメソッドの返値型の派生型にできない」

けれど、これは今現在C#のデザインの仕様変更の検討候補に上がっていて、将来的に仕様が変わるかも。

これが変わると、嬉しい例がある。

(おまけ)ILだと、同じ名前・同じ引数の型の順序で、違う返値型のメソッドをもてる

ちなみに

C#的には「同じ名前・同じ引数の型の順序で、違う返値型のメソッド」をもてない。

けれど、

IL(中間言語)だと、「同じ名前・同じ引数の型の順序で、違う返値型のメソッド」をもてる。

16
7
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?