web-dev-qa-db-ja.com

実装クラスからC#インターフェイスのデフォルトメソッドを呼び出す

C#8は、インターフェイスでのデフォルトのメソッド実装をサポートしています。私の考えは、ロギングメソッドを次のようなクラスに注入することでした。

public interface ILoggable {
    void Log(string message) => DoSomethingWith(message);
}

public class MyClass : ILoggable {
    void MyMethod() {
        Log("Using injected logging"); // COMPILER ERROR
    }
}

コンパイラエラーが表示されます:「名前が現在のコンテキストに存在しません」

この方法でデフォルトのメソッド実装を使用することは不可能ですか?

編集:

C#ルールに関する正しい応答については、 受け入れられた回答 を参照してください。より簡潔な解決策(私の質問の元のアイデア!)については、以下の私の 自分の答え を参照してください。

7
Andi

受け入れられた答えと他の応答は正しいです。しかし、私が欲しかったのは、Logメソッドの簡潔な呼び出しです。私はILoggableインターフェースの拡張メソッドでそれを達成しました:

_public static class ILoggableUtils { // For extension methods on ILoggable
    public static void Log(this ILoggable instance, string message) {
         DoSomethingWith(message, instance.SomePropertyOfILoggable);
    }
}
_

このようにして、醜い_((ILoggable)this).Log(...)_ではなく、少なくともクラスでthis.Log(...);を呼び出すことができます。

1
Andi

これらのデフォルトのメソッドについての記事を読むことから、私はそれをインターフェースにアップキャストすることを試みるべきだと思います:

((ILoggable)this).Log("Using injected logging")

私はそれをチェックしませんでした this 記事による私の考えだけ

1
Vladimir

煩雑で繰り返しのキャストを避けたい場合は、型をインターフェースとしてキャストする単一のプロパティを追加できます。

public class MyClass : ILoggable 
{
    ILoggable AsILoggable => (ILoggable)this;
    void MyMethod() 
    {
        AsILoggable.Log("Using injected logging"); 
    }
}

しかし、これはoffです。それがどのように行われたかに関係なく、それは間違っているようです。ドキュメントから:

最も一般的なシナリオは、すでにリリースされ無数のクライアントによって使用されているインターフェースにメンバーを安全に追加することです。

以前は実装されていなかったインターフェースに実装があることに何らかの懸念があったとき、これはそれを理解した文でした。これは、すでに実装しているクラスを壊すことなく、インターフェースに追加する方法です。

この質問は、新しいメソッドの「認識」を持つようにクラスを変更していることを意味します。言い換えると、暗黙の制約とは、何らかの理由でクラスを変更して新しいインターフェイスメソッドに対応することが実際的でないということです。新しいメソッドに依存するようにクラスを変更すると、まったく逆になります。

クラスを既に変更している場合は、メソッドを実装しないでください。

public void Log(string message) => DoSomethingWith(message);

デフォルトのインターフェース実装を追加すると、インターフェースのコンシューマー、つまり抽象化に依存するクラスに実装が提供されます。

withinからのデフォルトのインターフェース実装に依存している場合、インターフェースを実装するクラスは、インターフェースへの変更が実際にはクラスの内部実装。それはインターフェースの目的ではありません。インターフェイスは、内部実装ではなく、外部に面する動作を表します。

それは、クラスがそれ自体の外にステップインし、それ自体を外部コンシューマーとして振り返り、それを内部実装の一部として使用するかのようです。クラスはインターフェースを実装していませんが、インターフェースに依存しています。それは変だ。

私はそれが間違っているとは言いませんが、機能の乱用のように感じます

1
Scott Hannen