不思議な継承の変更

私は.NETの開発者であり、OOPについてほとんど知っています。 しかし、最近私は興味深い事実に気づいた。

System.Data.SqlClient.SqlCommand derives from System.Data.Common.DbCommand. The latter implements System.IDbCommand. System.IDbCommand exposes the property Connection which an instance of IDbConnection. In DbCommand However this property returns DbConnection type. And finally the same property in SqlCommand is of type SqlConnection

私は同じことを実行しようとしましたが、コンパイル時にエラーが出ました。上記の例でこれはどのように達成されたのですか?同じパターンを再現するにはどうしたらいいですか?

私のコード(コンパイルしていない):

public interface IFoo { }
public interface IBar 
{
   IFoo TheFoo();
}

public abstract class AbsFoo : IFoo { }
public abstract class AbsBar : IBar 
{
    public abstract AbsFoo TheFoo();
}

public class ConcreteFoo : AbsFoo { }
public class ConcreteBar : AbsBar { }
1
SqlCommand の機能を実行するには、Jasonの Richardの答えの両方を使用する必要があります。どちらの答えも全体の2つの部分です。
追加された 著者 Enigmativity,

3 答え

Explicit interface implementation is the name of the game here. Try this:

public abstract class AbsBar : IBar {
    IFoo IFoo.TheFoo() { return this.TheFoo(); }
    public abstract AbsFoo TheFoo();
}

に関する優れたガイドがあります暗黙的な実装と明示的な実装

4
追加された
オイベック:正しい。
追加された 著者 jason,
明示的なインタフェースの実装のために隠れています! (そして、コンパイルエラーのため申し訳ありません;私は途中でカットアンドペーストしますが、私を許してください。)ドキュメントは間違っていません。
追加された 著者 jason,
@ジェイソン - ここでは質問の半分に答えました。リチャードの答えは後半だった。 OPは、 SqlCommand の目的を達成するために、明示的なインタフェース実装メソッドのシャドウイングの両方を使用する必要があります。
追加された 著者 Enigmativity,
これは正しくなく、コンパイルされません。 Implict対explict実装では問題は解決しません。
追加された 著者 Richard Hein,
@ Jasonディレクティブを使用するのは何ですか?あなたのコードはコンパイルされません。また、Connectionが単にパブリックプロパティであるため、SqlCommandがConnectionに別の型を返すことができるのはDbCommandです。あなたはコンパイルエラーが "修飾子 '抽象的な'はこの項目に対して有効ではありません"。ドキュメントが間違っている、オブジェクトブラウザを見て、DbCommand.Connectionの署名が公開されていることを確認します。DbConnection Connection {get;セット; }、SqlCommand.Connectionのシグネチャはpublicです。SqlConnection Connection {get;セット; }。私はそれを正しく見ている。
追加された 著者 Richard Hein,
さらに、Object BrowserのSqlCommandを見て、Show Inherited Membersをオンにすると、DbConnectionと他のSqlConnectionを返すConnectionプロパティが2つ表示されますが、DbConnectionを返すものは通常のアクセスから隠れています。
追加された 著者 Richard Hein,
私は抽象クラスとして IBar.TheFoo()をマークしていますが、2番目のメソッドはpublic abstractとしてマークしていますが、
追加された 著者 Oybek,
申し訳ありませんが、明示的に宣言されたメソッドを実装する必要があることがわかります。私はそれを抽象的にすることはできません。
追加された 著者 Oybek,

I have to say that I think Richard was a little hard done by - his answer is just as good as Jason's in that they both only answered half of the question. Put them both together and you have the full answer.

To make this work with IDbCommand, DbCommand & SqlCommand there has to be an explicit implementation of IDbCommand in DbCommand (Jason's answer) and public method shadowing in SqlCommand (Richard's answer).

完全な "Foo/Bar"の例を挙げます。

これらのインタフェースから始めてください:

public interface IFoo
{
    IBar GetBar();
}

public interface IBar { }

次の IBar ではなく、 Bar を返すために、 FooIFoo code> GetBar メソッド:

public abstract class Foo : IFoo
{
    IBar IFoo.GetBar()
    {
        return this.GetBar();
    }

    public Bar GetBar()
    {
        return this.GetBarInner();
    }

    protected abstract Bar GetBarInner();
}

public abstract class Bar : IBar { }

最後に、 SomeFoo インスタンスを返すには、 SomeFoo クラスをシャドーして GetBar

public class SomeFoo : Foo
{
    public new SomeBar GetBar()
    {
        return new SomeBar();
    }

    protected override Bar GetBarInner()
    {
        return this.GetBar();
    }
}

public class SomeBar : Bar { }

私はリチャード氏がシャドーメソッドに new キーワードを追加してコンパイラエラーを取り除くという唯一の情報だと思います。

2
追加された
第三者の観測のための万華鏡。 :)
追加された 著者 Richard Hein,

DbCommandとSqlCommandでの接続は、どちらもパブリックメソッドです。コンパイラの警告がありますが、許可されています。あなたのコードはSqlCommand/DbCommandのように動作するようなものでなければなりません:

    public interface IFoo { }
public abstract class AbsBaseBar
{
    public IFoo TheFoo() { throw new NotImplementedException(); }
}
public class AbsFoo : IFoo { }
public class AbsBar : AbsBaseBar
{
    public AbsFoo TheFoo() { throw new NotImplementedException(); }
}

public class ConcreteFoo : AbsFoo { }
public class ConcreteBar : AbsBar { } 
1
追加された
私はあなたがリチャードによって少し難しいと思っています - あなたは質問の半分にかなり正確に答えました。ジェイソンはあなたの半分を完全に逃した。私は否定を取り除くためにあなたにアップヴォートを与えました。
追加された 著者 Enigmativity,