I really loved the idea of default implementations on interfaces in C#8. But after trying it the disappointment was big...
So here's a simple example which I've found a part of the answer to in C#8 interfaces with properties/methods defined in them - apparently not working already why this is:
public interface IHasFirstNames
{
string? FirstName => FirstNames.FirstOrDefault();
List<string> FirstNames { get; }
}
public class Monster : IHasFirstNames
{
public List<string> FirstNames { get; } = new();
public Monster(params string[] firstNames)
{
FirstNames.AddRange(firstNames);
}
}
public static class Program
{
public static void Main()
{
var sally = new Monster("James", "Patrick");
var error = sally.FirstName; // Cannot resolve symbol FirstName
var works = ((IHasFirstNames)sally).FirstName;
}
}
But whats the point of having a default implementation of a property in an interface if you always have to cast it ugly?!
So according to the casting-solution of above I've tried this:
public interface IHasFirstNames
{
string? FirstName => FirstNames.FirstOrDefault();
List<string> FirstNames { get; }
}
public class Monster : IHasFirstNames
{
// Not ideal to declare the property here
// But at least the implementation is still in the interface
public string? FirstName => ((IHasFirstNames)this).FirstName;
public List<string> FirstNames { get; } = new();
public Monster(params string[] firstNames)
{
FirstNames.AddRange(firstNames);
}
}
public static class Program
{
public static void Main()
{
var sally = new Monster("James", "Patrick");
var error = sally.FirstName; // StackOverflow!
}
}
But against expectations this leads to a stack overflow as the cast to IHasFirstName
does not really call the default implementation of the interface.
Even when I implement a full getter with a dedicated variable of type IHasFirstName
it leads to a stack overflow.
The only ugly solution I've come up with is this with a dedicated getter method:
public interface IHasFirstNames
{
// Default implementation of a property is no use to me!
string? FirstName { get; }
// So I have to implement a getter method as default
public string? FirstNameGetter() => FirstNames.FirstOrDefault();
List<string> FirstNames { get; }
}
public class Monster : IHasFirstNames
{
public string? FirstName => ((IHasFirstNames)this).FirstNameGetter();
public List<string> FirstNames { get; } = new();
public Monster(params string[] firstNames)
{
FirstNames.AddRange(firstNames);
}
}
public static class Program
{
public static void Main()
{
var sally = new Monster("James", "Patrick");
var works= sally.FirstName;
}
}
It doesn't have to be a method. Apparently it's also OK if its a property with a different name. Once the property in the interface and in the class should have the same name it gets ugly.
Is there really no nicer solution for this?
thanks
As others have pointed out, this isn't really the intended usage for default interface methods. As the documentation states:
For the way you want to use it, there's another mechanism available: Static extension methods. As you're probably already aware, this mechanism is used extensively in the CLR for things such as
IEnumerable<T>
extension methods.For your case, you could include the following static extension class alongside the interface:
If you use that instead of the declaration in the interface itself, your code will work as expected.
However, this does of course suffer from the major drawback that implementing classes cannot change the implementation! If you want to support that, you need to use abstract base classes instead:
Note that in this usage pattern, your implementing classes always derive from
HasFirstNamesBase
to make use of the default implementation.Derived classes can override the implementation:
Then: