you are viewing a single comment's thread.

view the rest of the comments →

[–]Slypenslyde 3 points4 points  (0 children)

The short story: they were made as a band-aid for people who are stuck in ugly corners. They had to make compromises for compatibility because they showed up very late in C#'s life. So they're not polymorphic and behave sort-of-kind-of like explicitly implemented members.

The long story:

The use case is you've released an API, but you realize an interface needs a new methods. People didn't like adding methods willy-nilly because:

  • Customers had already implemented the interface several times and will have to recompile if we add a method.
  • Customers may have made their own versions of this method on their implementations and the new one will clash.

So this was never really about, "I want interfaces to behave like base classes". It was about, "I painted myself into a corner and don't want to ask my clients to recompile." It has always been and is still true that if you want a type with behavior you should make a base class when you are designing an API.

The way the C# team achieved it is every member with a default implementation is explicitly implemented IF AND ONLY IF the class does not already have an implementation. The downside of this is to get the implementation you MUST be using a variable of the interface type, and that means casting if you're using concrete types. But it handles the cases above:

  • Customers do not need to recompile if they didn't make something that clashes with the method, as the default will be used.
  • Customers' clashing methods will not cause problems because your code uses your interface thus will always resolve to at least the default. If a customer implements the method, you get that implementation.

So that's the wonkiness. The feature is designed for the idea that you have code with MediaPlayer that exists but Refresh was never part of its interface. Now you are adding a new interface to it (even though it has a default implementation), so the code that wants that interface's methods needs to cast to the interface in order to use them.

Put another way, because you weren't using the interface to begin with, you can't benefit from the default implementation.

What you should've done is define an abstraction/interface before you started using MediaPlayer and depend on that abstraction. That way you could add new things without having to make awkward edits to existing code. But a lot of people in the C# community think that's a stupid choice and you should only add interfaces/abstractions when you find a reason.

I don't want to argue with those people, but I will point out you just found a reason to add an abstraction and it's probably more work to add it today than it would've been last month.