With C#8 Microsoft introduced Default Implementation for interface methods. It's still a fairly new feature and there seem to be many concerned bloggers writing about this.
What I'm wondering is if Default Implementation has the potential to be a helpful tool for Dependency Inversion and DI or if it promotes a bad programming style? Does it break any of the well known principles like SOLID?
There's two main design goals of default interface implementation. The more important goes all the way back to guidelines about designing interfaces. In particular, as soon as you publish an interface, it should be set in stone and never ever change. The problem is, this is also a rule that's ignored about... all of the time.
The first and main utility is that default interface implementation allows you to introduce new members into an interface, without breaking source or binary compatibility with consumers of that (public) interface. This still limits the kind of changes you can do when changing a public interface, but also makes it easier for clients to use the new interface - upgrading is free, and they can start using the new features right away.
The second design goal is a way to extend classes with traits - this has long been used in game development. The basic idea is that you can add new well-defined behaviours to a class just by having it implement an interface, while also retaining the ability to modify the behaviour in the class itself. This is essentially a relatively weak form of meta-programming.
Of course, just because those were the design goals doesn't mean that they are the only way you should use default implementations. But if you generalize a bit, you get these two basic uses:
In fact, you could even argue that this is both simpler, clearer and more powerful than class inheritance. In a way, this is a continuation of the approach started with extension methods - in essence, default interface method implementation is an extension method which is also virtual. The default implementation can only work with the public interface, but an implementing class can also use its own hidden state. It gives C# a limited form of multiple inheritance, without having to deal with how the state of two "parents" is joined together (since interfaces don't have any state).
Finally, if you're worried about principles like SOLID, let's give that a go: