1. ホーム
  2. c#

[解決済み] C#は戻り値の共分散をサポートしていますか?

2023-03-17 14:55:13

質問

私は.NETフレームワークで作業しており、私のウェブサイトのすべてが使用するカスタムタイプのページを作ることができるようにしたいと思います。問題は、私がコントロールからページにアクセスしようとしているときに起こります。私は、デフォルトのページの代わりに、私の特定のタイプのページを返すことができるようにしたいです。これを行う方法はありますか?

public class MyPage : Page
{
    // My own logic
}

public class MyControl : Control
{
    public MyPage Page { get; set; }
}

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


UPDATE: この回答は2011年に書かれました。20 年以上にわたって C# の戻り値の共変性を提案してきた結果、実装されました。C# の共変数戻り値 を参照してください。 https://devblogs.microsoft.com/dotnet/c-9-0-on-the-record/ .


あなたが欲しいのは戻り値の共分散のようですね。C# は戻り値の共分散をサポートしていません。

戻り値の共変性は、あまり特定されていない型を返す基底クラスのメソッドを、より特定された型を返すメソッドでオーバーライドすることです。

abstract class Enclosure
{
    public abstract Animal Contents();
}
class Aquarium : Enclosure
{
    public override Fish Contents() { ... }
}

これは、Contents via Enclosureの消費者がAnimalを期待しているからであり、Aquariumはその要求を満たすだけでなく、さらに、Animalは必ず魚であるという、より厳格な約束をしているため安全である。

この種の共分散はC#ではサポートされていませんし、今後もサポートされることはないでしょう。また、CLR でもサポートされていません。 (C++ と CLR 上の C++/CLI 実装ではサポートされています。私が以下で提案する種類の魔法のヘルパー メソッドを生成することによって、サポートされています)。

(いくつかの言語では、正式なパラメータータイプの連続性を同様にサポートします。つまり、Fish を受け取るメソッドを Animal を受け取るメソッドでオーバーライドできます。ベースクラスはどんな魚でも処理することを要求し、派生クラスは魚だけでなくどんな動物でも処理することを約束するのです。同様に、C#とCLRは正式なパラメータ型の連続性をサポートしていません)。

この制限を回避する方法は、次のようなものです。

abstract class Enclosure
{
    protected abstract Animal GetContents();
    public Animal Contents() { return this.GetContents(); }
}
class Aquarium : Enclosure
{
    protected override Animal GetContents() { return this.Contents(); }
    public new Fish Contents() { ... }
}

これで、仮想メソッドをオーバーライドする利点と、コンパイル時の型Aquariumの何かを使用する際に強い型付けを得ることの両方を得ることができます。