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
IHasFirstName sally = new Monster("James", "Patrick");
– BirettaIHasFirstName sally = new Monster("James", "Patrick");
is clear - which is not practicle in real life as I loose the ability to access other properties of the classMonster
via the instancesally
. So it seems that DIMs are kinda named wrongly at least for my expectations. Then a "default interface member" should help me (DRY principle) not to dopublic string? FirstName => FirstNames.FirstOrDefault();
each and every time on all classes who implementIHasFirstName
. – Chromatic((IHasFirstNames)sally).FirstName
works perfectly, but if I do the same inside theMonster
class with((IHasFirstNames)this).FirstName
it does not work! – Chromatic((IHasFirstNames)this).FirstName
you're calling your current class's implementation at that point, not the base class.public string? FirstName =>
implements the interface, sopublic string? FirstName =>((IHasFirstNames)this).FirstName;
is calling itself. Again, you'd have the same issue with any method. Unless you explicitly implemented the member withpublic string? IHasFirstNames.FirstName ->...
. To call the base implementation you'd need=> base.FirstName
which is planned but not implemented yet – Biretta