Frederik Today

Adding Default Behaviour to Interfaces in dotNet

A strange question you may think, as interfaces define a contract and every class (or struct) that implements that interface must provide an implementation of the member's methods.

Why Adding Extension to an Interface

When you have an Interface, used by many classes, and you want to add a method, this means you need to update all your classes implementing the interface, including testing.

This is not always the preferred way as it can be time-consuming and not all classes will be using the new method.
Default Behaviour is good for backwards compatibility

Default Behaviour for Interfaces with C#8

public interface ISearchResult
{
string GetPublicUrl();
string GetTitle();
string GetDescription();

public void GetAuthorName(Exception ex)
{
return "";
}
}

Author Class

The Author Class doesn't need the Author Class, as the GetTitle will return the Name
public sealed class Author : ISearchResult
{
public string? Name { get; set; }
public string? Intro { get; set; }
public string? AuthorHandler { get; set; }

public string GetPublicUrl()
{
return "https://mydomain.conm/author/" + AuthorHandler;
}
public string GetTitle()
{
return this.Name;
}
public string GetDescription()
{
return this.Intro;
}
}

Article Class

The article class implemented the GetAuthorName
public sealed class Article : ISearchResult
{
public string? Title { get; set; }
public string? FriendlyUrl { get; set; }
public string? ShortIntro { get; set; }
public Author AuthorInfo { get; set; }

public string GetPublicUrl()
{
return "https://mydomain.com/article/" + FriendlyUrl;
}
public string GetTitle()
{
return this.Title;
}

public string GetDescription()
{
return this.ShortIntro;
}
public string GetAuthorName()
{
return " by " + this.AuthorInfo.Name;
}
}

The App

List<ISearchResult> _searchResults = new() { 
new Author() { Name="Ernest Hemmingway", Intro= "Ernest Miller Hemingway was an American novelist, short-story writer, and journalist.", AuthorHandler="@ernesthemmingway" },

new Author() { Name="Stephen King", Intro= "Stephen Edwin King is an American author of horror, supernatural fiction, suspense, crime, science-fiction, and fantasy novels. ", AuthorHandler="@stephenking" }

};

Article _article1 = new() { Title = "It", FriendlyUrl = "stephen-king-it", ShortIntro = "The story follows the experiences of seven children as they are terrorized by an evil entity that exploits the fears of its victims to disguise itself while hunting its prey" };
article1.AuthorInfo.Name = "Stephen King";
searchResults.Add(_article1);

//-- Show the results:
foreach(var _result in searchResults)
{
Console.WriteLine(
result.GetTitle() + _result.GetAuthorName());
}

The Results

As you can see, even though we didn't implement the method GetAuthorName in the Author Class, the default is used inside the Interface (returning an empty string in our case)
Ernest Hemmingway
Stephen King
It by Stephen King

Conclusion

Adding default behaviour to the Interface guarantees backward compatibility. Certainly when your interface is used by many classes and you need to add functionality to a few, like in the case of search results