Multiple Interface Inheritance

Just as classes can implement multiple interfaces, so interfaces can inherit from multiple interfaces. The syntax used for this purpose is consistent with class derivation and implementation, as shown in Listing 8.9.

Listing 8.9: Multiple Interface Inheritance
1. interface IReadableSettingsProvider
2. {
3.     string GetSetting(string name, string defaultValue);
4. }
5.  
6. interface IWriteableSettingsProvider
7. {
8.     void SetSetting(string name, string value);
9. }
10.  
11. interface ISettingsProvider : IReadableSettingsProvider,
12.     IWriteableSettingsProvider
13. {
14. }

It is unusual to have an interface with no members, but it is a reasonable choice when implementing both interfaces together. The difference between Listing 8.9 and Listing 8.6 is that it is now possible to implement IWriteableSettingsProvider without supplying any read capability. Listing 8.6’s FileSettingsProvider is unaffected. If it used explicit member implementation, however, specifying the interface to which a member belongs changes slightly.

Extension Methods on Interfaces

Perhaps one of the most important features of extension methods is the fact that they work with interfaces in addition to classes. The syntax used is identical to that used for extension methods for classes. The extended type (the first parameter and the parameter prefixed with this) is the interface that we extend. Listing 8.10 shows an extension method for IListable() that is declared on the Listable class.

Listing 8.10: Interface Extension Methods
1. public class Program
2. {
3.     public static void Main()
4.     {
5.         Contact[] contacts = new Contact[] {
6.             new(
7.                 "Dick""Traci",
8.                 "123 Main St., Spokane, WA  99037",
9.                 "123-123-1234")
10.             // ...
11.         };
12.  
13.         // Classes are implicitly converted to
14.         // their supported interfaces
15.         contacts.List(Contact.Headers);
16.  
17.         Console.WriteLine();
18.  
19.         Publication[] publications = new Publication[3] {
20.             new("The End of Poverty: Economic Possibilities for Our Time",
21.                 "Jeffrey Sachs", 2006),
22.             new("Orthodoxy"
23.                 "G.K. Chesterton", 1908),
24.             new(
25.                 "The Hitchhiker's Guide to the Galaxy",
26.                 "Douglas Adams", 1979)
27.             };
28.         publications.List(Publication.Headers);
29.     }
30. }
31.  
32. public static class Listable
33. {
34.     public static void List(
35.         this IListable[] items, string[] headers)
36.     {
37.         int[] columnWidths = DisplayHeaders(headers);
38.  
39.         for(int itemCount = 0; itemCount < items.Length; itemCount++)
40.         {
41.             if (items[itemCount] is not null)
42.             {
43.                 string?[] values = items[itemCount].CellValues;
44.  
45.                 DisplayItemRow(columnWidths, values);
46.             }
47.         }
48.     }
49.     // ...
50. }

In this example, the extension method is not for an IListable parameter (although it could have been), but rather for an IListable[] parameter. This demonstrates that C# allows extension methods not only on an instance of a particular type but also on a collection of those objects. Support for extension methods is the foundation on which the Language Integrated Query (LINQ) capability is implemented. IEnumerable is the fundamental interface that all collections implement. By defining extension methods for IEnumerable, LINQ support was added to all collections. This radically changed programming with collections. We explore this topic in detail in Chapter 15.

Beginner Topic
Interface Diagramming

Interfaces in a UML-like7 figure take two possible forms. First, you can show the interface as though it is an inheritance relationship similar to a class inheritance, as demonstrated in Figure 8.1 between IPerson and IContact. Alternatively, you can show the interface using a small circle, often referred to as a lollipop, exemplified by IPerson and IContact in Figure 8.1.

In Figure 8.1, Contact derives from PdaItem and implements IContact. In addition, it aggregates the Person class, which implements IPerson. Although the Visual Studio Class Designer does not support this practice, interfaces are sometimes shown as using a derivation-type arrow to a class. For example, Person could have an arrow to IPerson instead of a lollipop.

Figure 8.1: Working around single inheritance with aggregation and interfaces.

________________________________________

7. Unified Modeling Language (UML), a standard specification for modeling object design using graphical notation.
{{ snackbarMessage }}
;