You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Fixesdotnet#41491
Clarified the diamond problem with default interface methods. Add an image to illustrate the problem, and provide additional text explanation.
* Fixesdotnet#40808
Remove the (now) obsolete paragraph.
* Fixesdotnet#41507
Clarify how extra braces are processed in interpolated raw string literals.
* Fixesdotnet#41538
Add collection expressions to the member access article. Include links to the collection expressions article.
* Fixesdotnet#30876
Add important note that an instance constructor called from a static field initializer in the same type that invokes an instance constructor means the instance constructor is called before the static constructor.
* Fixesdotnet#41629
Note that the order of static constructor execution isn't specified.
Perform a final edit pass.
* build fix
* Update docs/csharp/programming-guide/strings/index.md
Copy file name to clipboardExpand all lines: docs/csharp/advanced-topics/interface-implementation/mixins-with-default-interface-methods.md
+14-8Lines changed: 14 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,13 +1,13 @@
1
1
---
2
2
title: Create mixin types using default interface methods
3
3
description: Using default interface members you can extend interfaces with optional default implementations for implementors.
4
-
ms.date: 03/17/2023
4
+
ms.date: 07/31/2024
5
5
---
6
6
# Tutorial: Mix functionality in when creating classes using interfaces with default interface methods
7
7
8
8
You can define an implementation when you declare a member of an interface. This feature provides new capabilities where you can define default implementations for features declared in interfaces. Classes can pick when to override functionality, when to use the default functionality, and when not to declare support for discrete features.
9
9
10
-
In this tutorial, you'll learn how to:
10
+
In this tutorial, you learn how to:
11
11
12
12
> [!div class="checklist"]
13
13
>
@@ -27,11 +27,11 @@ Extension methods are resolved at compile time, using the declared type of the v
27
27
28
28
You can declare the default implementations as interface methods. Then, every class automatically uses the default implementation. Any class that can provide a better implementation can override the interface method definition with a better algorithm. In one sense, this technique sounds similar to how you could use [extension methods](../../programming-guide/classes-and-structs/extension-methods.md).
29
29
30
-
In this article, you'll learn how default interface implementations enable new scenarios.
30
+
In this article, you learn how default interface implementations enable new scenarios.
31
31
32
32
## Design the application
33
33
34
-
Consider a home automation application. You probably have many different types of lights and indicators that could be used throughout the house. Every light must support APIs to turn them on and off, and to report the current state. Some lights and indicators may support other features, such as:
34
+
Consider a home automation application. You probably have many different types of lights and indicators that could be used throughout the house. Every light must support APIs to turn them on and off, and to report the current state. Some lights and indicators might support other features, such as:
35
35
36
36
- Turn light on, then turn it off after a timer.
37
37
- Blink the light for a period of time.
@@ -68,7 +68,7 @@ The `OverheadLight` class can implement the timer function by declaring support
68
68
publicclassOverheadLight : ITimerLight { }
69
69
```
70
70
71
-
A different light type may support a more sophisticated protocol. It can provide its own implementation for `TurnOnFor`, as shown in the following code:
71
+
A different light type might support a more sophisticated protocol. It can provide its own implementation for `TurnOnFor`, as shown in the following code:
@@ -96,7 +96,7 @@ The `HalogenLight` you created earlier doesn't support blinking. So, don't add t
96
96
97
97
## Detect the light types using pattern matching
98
98
99
-
Next, let's write some test code. You can make use of C#'s [pattern matching](../../fundamentals/functional/pattern-matching.md) feature to determine a light's capabilities by examining which interfaces it supports. The following method exercises the supported capabilities of each light:
99
+
Next, let's write some test code. You can make use of C#'s [pattern matching](../../fundamentals/functional/pattern-matching.md) feature to determine a light's capabilities by examining which interfaces it supports. The following method exercises the supported capabilities of each light:
@@ -116,6 +116,12 @@ The default implementation assumes no power:
116
116
117
117
These changes compile cleanly, even though the `ExtraFancyLight` declares support for the `ILight` interface and both derived interfaces, `ITimerLight` and `IBlinkingLight`. There's only one "closest" implementation declared in the `ILight` interface. Any class that declared an override would become the one "closest" implementation. You saw examples in the preceding classes that overrode the members of other derived interfaces.
118
118
119
-
Avoid overriding the same method in multiple derived interfaces. Doing so creates an ambiguous method call whenever a class implements both derived interfaces. The compiler can't pick a single better method so it issues an error. For example, if both the `IBlinkingLight` and `ITimerLight` implemented an override of `PowerStatus`, the `OverheadLight` would need to provide a more specific override. Otherwise, the compiler can't pick between the implementations in the two derived interfaces. You can usually avoid this situation by keeping interface definitions small and focused on one feature. In this scenario, each capability of a light is its own interface; only classes inherit multiple interfaces.
119
+
Avoid overriding the same method in multiple derived interfaces. Doing so creates an ambiguous method call whenever a class implements both derived interfaces. The compiler can't pick a single better method so it issues an error. For example, if both the `IBlinkingLight` and `ITimerLight` implemented an override of `PowerStatus`, the `OverheadLight` would need to provide a more specific override. Otherwise, the compiler can't pick between the implementations in the two derived interfaces. This situation is shown in the following diagram:
120
120
121
-
This sample shows one scenario where you can define discrete features that can be mixed into classes. You declare any set of supported functionality by declaring which interfaces a class supports. The use of virtual default interface methods enables classes to use or define a different implementation for any or all the interface methods. This language capability provides new ways to model the real-world systems you're building. Default interface methods provide a clearer way to express related classes that may mix and match different features using virtual implementations of those capabilities.
121
+
:::image type="content" source="./media/mixins-with-default-interface-methods/diamond-problem.svg" alt-text="illustration of the diamond problem with default interface methods":::
122
+
123
+
The preceding diagram illustrates the ambiguity. `OverheadLight` doesn't provide an implementation of `ILight.PowerStatus`. Both `IBlinkingLight` and `ITimerLight` provide overrides that are more specific. A call to `ILight.PowerStatus` on an instance of `OverheadLight` is ambiguous. You must add a new override in `OverheadLight` to resolve the ambiguity.
124
+
125
+
You can usually avoid this situation by keeping interface definitions small and focused on one feature. In this scenario, each capability of a light is its own interface; only classes inherit multiple interfaces.
126
+
127
+
This sample shows one scenario where you can define discrete features that can be mixed into classes. You declare any set of supported functionality by declaring which interfaces a class supports. The use of virtual default interface methods enables classes to use or define a different implementation for any or all the interface methods. This language capability provides new ways to model the real-world systems you're building. Default interface methods provide a clearer way to express related classes that might mix and match different features using virtual implementations of those capabilities.
0 commit comments