「C Sharpの基礎 - インターフェイス」の版間の差分

ナビゲーションに移動 検索に移動
525行目: 525行目:
* 派生インターフェイスでのオーバーライドは明示的実装が必須。
* 派生インターフェイスでのオーバーライドは明示的実装が必須。
* 標準実装を持つメンバは、派生クラスまたは派生インターフェイスから直接呼べない。(親へのキャストが必要)
* 標準実装を持つメンバは、派生クラスまたは派生インターフェイスから直接呼べない。(親へのキャストが必要)
<br>
C# 8.0(.NET Core 3.0)以降、インターフェイスは実装を持つことができる。<br>
<syntaxhighlight lang="c#">
interface I
{
    void X();
    void Y()  // 標準実装を持っているため、コンパイル可能
    { }
}
class A : I
{
    public void X()  // Xメソッドのみ実装する
    { }
}
class B : I
{
    public void X() { }
    public void Y() => Console.WriteLine("B");  // Yメソッドも実装できる
}
</syntaxhighlight>
<br>
ただし、以下の制限は存在する。<br>
* フィールドを持つことはできない。(静的フィールドは可能)
* コンストラクタおよびデストラクタは持つことができない。(静的コンストラクタは可能)
<br>
以下に、C# 8.0(.NET Core 3.0)以降、インターフェイスで緩和された項目を示す。<br>
<br>
==== 静的メンバ ====
静的メンバ、静的コンストラクタ、静的フィールドを持つことができる。<br>
また、定数、演算子、入れ子の型も持つことができる。<br>
<br>
アクセス修飾子は、protected、privateを指定することができる。指定しない場合、publicとなる。<br>
<syntaxhighlight lang="c#">
using System;
interface I
{
    static I()
    { }
    static int _field;
    static int Method() => ++_field;
    const int Constant = 1;
    public static I operator +(I x) => x;
    class Inner { }
}
class Program
{
    static void Main()
    {
      Console.WriteLine(I.Method());
      I.Inner inner;
    }
}
</syntaxhighlight>
<br>
==== アクセス修飾子 ====
C# 7.3以前は、インターフェイスのメンバは常にvirtualかつpublicであった。<br>
C# 8.0以降、明示的に指定することで、protected、private等のアクセス修飾子を指定できる。<br>
<br>
protectedメンバにアクセスできるのは、派生インターフェイスのみである。<br>
インターフェイスを実装(派生)しているクラスの場合、protectedメンバにはアクセスできない。<br>
<syntaxhighlight lang="c#">
interface I
{
    void Public()
    {
        Private();
    }
    // アクセス修飾子を指定できる
    // protectedの場合、派生インターフェイスからのみ呼び出すことができる
    // privateの場合、自身からのみ呼び出すことができる
    protected void Protected() { }
    private void Private() { }
}
interface IDerived : I
{
    void M()
    {
      Public();
      Protected();
      // Private();
    }
}
</syntaxhighlight>
<br>
==== 既定で仮想 ====
protectedやinternal等を付加する場合、自動的にprotected virtualやinternal virtualとなる。<br>
privateやsealedを指定する場合のみ、非仮想となる。<br>
<syntaxhighlight lang="c#">
interface I
{
    // 未指定の場合、public virtual
    void Public()
    { }
    // protectedを指定する場合、protected virtual
    protected void Protected()
    { }
    // privateメンバは派生側から呼ばれないため、virtualである必要がない
    private void Private()
    { }
    // sealedを指定する場合、非virtualとなる
    sealed void Sealed()
    { }
}
</syntaxhighlight>
<br>
また、基底インターフェイスのvirtualメンバは、派生インターフェイスでsealedに変更することができない。<br>
virtualメンバは、常にvirtualとなる。<br>
<syntaxhighlight lang="c#">
interface IDerived : I
{
    // 基底インターフェイスのvirtualメンバは、派生インターフェイスでsealedに変更することができない
    // コンパイルエラー
    sealed void I.Protected()
    { }
}
</syntaxhighlight>
<br>
==== 多重継承 ====
例えば、以下のような記述では、どの実装を使用すべきか不明瞭であるため、コンパイルエラーが起きる。<br>
<syntaxhighlight lang="c#">
using System;
interface IA
{
    void M() => Console.WriteLine("A.M");
}
interface IB : IA
{
    void IA.M() => Console.WriteLine("B.M");
}
interface IC : IA
{
    void IA.M() => Console.WriteLine("C.M");
}
// IBおよびICにMメソッドの実装があるため、どちらを使用すべきか不明瞭である(コンパイルエラー)
class C : IB, IC
{
    // ...略
}
</syntaxhighlight>
<br>
ただし、クラス自身が実装を持つ場合はクラスのメソッドが優先されるため、コンパイルエラーは起きない。<br>
<syntaxhighlight lang="c#">
class C : IB, IC
{
    // IB.MまたはIC.Mではなく、このMが呼ばれるためコンパイル可能
    public void M() => Console.WriteLine("new implementation");
}
</syntaxhighlight>
<br>
C# 9.0では、特定の実装を呼ぶ場合、baseキーワードに特定の型を指定できる機能が追加される。<br>
baseキーワードは、クラスでも使用できる。<br>
<syntaxhighlight lang="c#">
class C : IB, IC
{
    // baseキーワードを使用することで、明示的にIB.Mメソッドを呼ぶことができる
    public void M() => base(IB).M();
}
</syntaxhighlight>
<br><br>
<br><br>


__FORCETOC__
__FORCETOC__
[[カテゴリ:C_Sharp]]
[[カテゴリ:C_Sharp]]

案内メニュー