Calling C# interface default method from implementing class
See the documentation at https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/default-interface-members-versions
That cast from
SampleCustomer
toICustomer
is necessary. TheSampleCustomer
class doesn't need to provide an implementation forComputeLoyaltyDiscount
; that's provided by theICustomer
interface. However, theSampleCustomer
class doesn't inherit members from its interfaces. That rule hasn't changed. In order to call any method declared and implemented in the interface, the variable must be the type of the interface,ICustomer
in this example.
So the method is something like
public class MyClass : ILoggable {
void MyMethod() {
ILoggable loggable = this;
loggable.Log("Using injected logging");
}
}
In CLR all interface member implementations are explicit, so in your code Log
will be available in instances of ILoggable
only, like it's recommended to do here:
((ILoggable)this).Log("Using injected logging")
If you want to avoid clutter and repetitive casting you can add a single property which casts the type as the interface:
public class MyClass : ILoggable
{
ILoggable AsILoggable => (ILoggable)this;
void MyMethod()
{
AsILoggable.Log("Using injected logging");
}
}
But this is off. It seems wrong, regardless of how it's done. From the documentation:
The most common scenario is to safely add members to an interface already released and used by innumerable clients.
When there was some concern about having implementations in interfaces - which previously had none - this was the sentence that made sense of it. It's a way to add to an interface without breaking classes that already implement it.
But this question implies that we are modifying the class to reflect a change to an interface it implements. It's the exact opposite of the stated use case for this language feature.
If we're already modifying the class, why not just implement the method?
public void Log(string message) => DoSomethingWith(message);
When we add a default interface implementation, we provide an implementation to consumers of the interface - classes that depend on an abstraction.
If we depend on the default interface implementation from within the class that implements the interface, then a change to the interface becomes, in effect, a change to the internal implementation of the class. That's not what an interface is for. An interface represents external-facing behavior, not internal implementation.
It's as if the class is stepping outside of itself, looking back in at itself as an external consumer, and using that as part of its internal implementation. The class doesn't implement the interface, but it depends on it. That's weird.
I won't go so far as to say that it's wrong, but it feels like an abuse of the feature.