Friday, September 27, 2019

C# 8 Interfaces: Unit Testing Default Implemetation

When taking a closer look at C# 8 interfaces, we need think about unit testing. We (potentially) have code in our interfaces; how do we test it?
We can test default implementations with our own fake objects, however, we cannot test them with mocking-framework objects (at least for now*).
Once we take a closer look at some tests and understand what mocking frameworks do for us, this will make a bit more sense. Hopefully our favorite frameworks will give us an easy way to test default implementations in the future, but for now we have to do things a bit more manually.

The code for this article is available on GitHub: jeremybytes/interfaces-in-csharp-8.

Note: this article uses C# 8 features, which are currently only implemented in .NET Core 3.0. For these samples, I used Visual Studio 16.3.1 and .NET Core 3.0.100.

This article uses 2 projects. UnitTests.Library is a .NET Standard 2.1 class library that contains the interface. UnitTests.Tests is a .NET Core 3.0 NUnit unit test project; this contains the tests.

*Update April 2022: The Moq mocking framework does now support testing default implementation by using the "CallBase" property (see notes in the Moq section below). In addition the Rocks framework (available on NuGet + GitHub repo) does support testing default implemented members. This framework was not included in my original survey, but I know the author, and he added the functionality after I showed him the issue.

Testing Default Implementation
I am a big believer in unit testing. When I put code into my projects, I think of how the code can be written so that it is easy to test. The same is true when it comes to default implementation in interfaces. The basics involve just a few steps.

An Interface
Here's the interface that we use for these tests, IRegularPolygon (from the IRegularPolygon file in the UnitTests.Library project):


This interface describes a regular polygon -- meaning, a shape that has 3 or more sides where each side is the same length. The "GetPerimeter" method has a default implementation, and this is what we want to test.

A Fake Object
For the first test, we will use a fake object. This is a manually-created class that implements the interface.

Here is the code for the FakeWithDefault class (from the IRegularPolygon.Tests.cs file in the UnitTests.Tests project):


This class provides implementations for the abstract members of the interface, but it does *not* provide an override for the GetPerimeter method. It relies on the default implementation from the interface.

A First Test
Now that we have the interface and an implementing class, we can write our first unit test. Here is the code for that (from the IRegularPolygon.Tests.cs file -- the rest of the code samples will come from this file):


This test creates an instance of our fake object and assigns it to an IRegularPolygon variable.

IMPORTANT:
It is important to specify that the variable is "IRegularPolygon". If we use "var" or "FakePolygonWithDefault" as the type, then the GetPerimeter method will not be accessible.

The next line calls the GetPerimeter method on the interface. This will use the default implementation.

The last line checks the value of the output. Our fake object uses the values of "4" and "5" for NumberOfSides and SideLength, respectively. So we expect that the value of GetPerimeter is 4 * 5, or 20.

This test passes:


So we can see that we can test a default implementation with just a few steps. We create a class that implements the interface but does not override the default implementations from the interface. In the test, we create an instance of that class and cast it to the interface. Finally, we call the member with the default implementation and check the result.

Testing with a Mocking Framework
Sometimes I manually create fake objects for my unit tests, but I generally use a mocking framework instead. This reduces the number of objects in the unit test projects. And once we're comfortable with a particular framework, we can quickly create test objects with a variety of configurations.

Unfortunately, we cannot test default implementation with the way that mocking frameworks work today. Let's start by looking at an example using Moq (the framework I generally turn to).

Creating a Mock with Moq
The test project includes a NuGet reference to the Moq package. With that in place, we can write a test that uses a mock object:


When using a mocking framework, we tell the framework how to create and configure our test object. The first line of our test creates a mock based on the IRegularPolygon interface.

The next two lines set up the mock with specific values for the NumberOfSides property and the SideLength property. In this case, if we ask the mock for "NumberOfSides", it will give us "3"; if we ask for "SideLength", it will give us "5".

The setup does *not* include configuration for the "GetPerimeter" or the "GetArea" methods. This is a key feature of mocking frameworks, and we'll discuss this further down.

The 4th line calls the "GetPerimeter" method on our mock object. (The variable "mock" is a "Mock<IRegularPolygon>". When using Moq, the "Object" property represents the "IRegularPolygon" object.)

The last line checks the results.

Failure
Unfortunately, we do not get the results we want.


This test fails. When we look at the Error Message, we see that the value was "0.0d" (meaning 0 as a double) instead of the expected "15.0d".

Expected Behavior
This is the expected behavior from Moq (and mocking frameworks in general). When we configure a mock object, we only need to fill in the items that we use. And that can be a big time saver, particularly if we need to quickly mock up a dependency needed for a test.

When we create an object manually (FakePolygonWithDefault), we need to provide implementations for all of the abstract members of the interface. This means that we have to provide an implementation for "GetArea" even though we do not use that method in the tests.

When we create a mock object using a framework, we only need to provide implementations for the things we care about. The mocking framework will take care of the rest.

In the unit test using Moq, we do not need to provide a configuration for the "GetArea" method because we do not use it in the tests. If, for some reason, a test calls the "GetArea" method, the mocking framework will return the default value. Since "GetArea" returns a double, the default value is "0.0d".

Does this value look familiar? We *are* using the "GetPerimeter" method in our tests. But instead of getting the default implementation from the interface, we are getting the default value from the mocking framework. Since "GetPerimeter" also returns a double, the default value is "0.0d". This is the value we see in the failing test.

***Update for Moq (April 2022)***
Moq has been updated to support calling default implementation for members. In order for the default implementation to be used, set the "CallBase" property on the mock object to "true".

Sample:
    var mock = new Mock<IRegularPolygon>();

    mock.CallBase = true;
    mock.SetupGet(m => m.NumberOfSides).Returns(3);
    mock.SetupGet(m => m.SideLength).Returns(5);

    double result = mock.Object.GetPerimeter();

    Assert.AreEqual(15.0, result);
This has the desired effect. The default implementation for "GetPerimeter" is called, and the test passes.
***End Update (April 2022)***

Explicit Configuration
We can explicitly configure the mock object with the "GetPerimeter" method:


And it works. This test passes:


But this does not use the default implementation; it uses an explicit implementation.

Other Frameworks
I tried a couple of other frameworks: NSubstitute and FakeItEasy. These both provided similar results.

NSubstitute
Here is a test using NSubstitute without an override of the default:


And with an override:


And the test results are similar to using Moq:


Again, this isn't a surprise if we understand how the mocking frameworks work.

FakeItEasy
Here is a test using FakeItEasy. First without an override of the default:


And with an override:


And the results:


Again, we see similar behavior to the other frameworks.

Will Mocking Frameworks Change?
All of this is still really new. C# 8 with default implementation released at the beginning of this week. So the fact that these mocking frameworks do not support default implementation by default is not surprising.

Will this change in the future?

I'm not sure. I have not done extensive searches. But in my preliminary search I haven't seen anything about default implementation, and these particular packages do not currently have pre-release versions on NuGet.

Update: As Blair Conrad notes in the comments, FakeItEasy has an open issue for supporting default implementation: Issue - Support for calling default interface members.

Here are the versions that I used for this project:


I will keep an eye on this because I'm curious how mocking frameworks will adjust with default implementation in interfaces.

It may be difficult to change the default behavior. If someone does *not* configure an interface member, do they expect to get the default value (current behavior) or the default implementation from the interface (new behavior)? Changing the current behavior could result in breaking changes.

***UPDATE (April 2022)***
As noted above, the current version of Moq (4.17.2) does support testing default implementation. Unfortunately, I do not know the exact version when the behavior was updated. The current version of FakeItEasy (7.3.1) does not support default implementation. The issue mentioned above is still open. I haven't dug into NSubstitute yet (it's on my list). The default behavior is still the same, but I need to see if there is a property or setting that makes it possible to test default implemented members.

Testing Manually
Whichever way the mocking frameworks go, we can test default implementations manually. We can create classes that do not override the default and then use those objects in our tests.

Default implementation in interfaces gives us a lot of new things to think about. I'm most concerned with how it affects the existing code, techniques, and processes that I already have (and other people have). Once we get the current things worked out, it will be easier to figure out how to move forward in the best way we can.

Happy Coding!

Thursday, September 26, 2019

C# 8 Interfaces: "dynamic" and Default Implementation

In taking a closer look at C# 8 interfaces, I ran across a bit of a bug when using "dynamic" with default implementation members.
A "dynamic" object cannot see interface members with only default implementations.
This is something I came across when exploring properties and default implementation. But it's interesting enough to warrant a closer look.

The code for this article is available on GitHub: jeremybytes/interfaces-in-csharp-8, specifically the DynamicAndDefaultImplementation project.

Note: this article uses C# 8 features, which are currently only implemented in .NET Core 3.0. For these samples, I used Visual Studio 16.3.1 and .NET Core 3.0.100.

An Interface with Default Implementation
To show how dynamic works (or doesn't work), we'll use an interface with a default implementation for a method. The example here is an interface that represents a regular polygon -- that is, a geometric shape with 3 or more sides where each side is the same length.

Here is the interface (from the IRegularPolygon.cs file):


The "GetPerimeter" method has a default implementation and uses the expression-bodied member syntax. Since the perimeter of a shape is calculated the same regardless of the number of sides, we can provide a default implementation in the interface. (Whether this is a good approach or not is going to be discussed in a future article.)

The Implementation
This interface is implemented by the Square class (from the Square.cs file):


As shown here, the Square class provides implementations for the NumberOfSides and SideLength properties from the interface, and it has an implementation of the GetArea method from the interface (this also uses the expression-bodied member syntax).

Notice that the GetPerimeter method is *not* implemented. The class instead relies on the default implementation provided by the interface.

Using the Implementation
This project is a console application, and the Main method creates two Square objects and displays them (from the Program.cs file -- the final file has some error handling that isn't shown here):


Showing Members with the Interface
Here is the "ShowInteracePolygon" method (also from the Program.cs file):


This method takes our interface as a parameter. Then it displays the properties and methods that are part of the interface. This method call works fine with both of our Square objects.

The first call is made with "smallSquare". Since "smallSquare" uses "var", the variable is a Square type. (For more information on "var", take a look at Demystifying the "var" Keyword in C#.) But because the parameter is "IRegularPolygon", the "smallSquare" gets cast to the interface for use in the method.

The second call is made with "largeSquare". This variable is explicitly typed as "IRegularPolygon", so there is no casting necessary when the method is called.

A Problem with Dynamic
The problem comes in with the "ShowDynamicPolygon" method. I have used "dynamic" in the past so that a method can work with various types that all have the same properties and methods even if the types are incompatible.

As a side note, I also like to use "dynamic" when I need to pick one or two values out of a deserialized JSON object. This saves me from having to create a separate class or do mapping. There are risks of runtime errors, but sometimes it is worth the risk.

Here is the code for ShowDynamicPolygon (also in the Program.cs file):


The body of the method is identical to "ShowInterfacePolygon". The only difference is that the parameter is typed as "dynamic".

Unfortunately, this fails.

Failure with the Concrete Type (Square)
The first call to this method (using "smallSquare") fails:


The exception is a RuntimeBinderException. This is thrown when the Runtime Binder cannot find the requested member on the object. In this case, the exception tells us that "GetPerimeter" is not part of the "Square" class.

And that is absolutely correct. If we look back at the Square class, we see that it does not have a "GetPerimeter" method:


So this failure makes sense.

Failure with the Interface (IRegularPolygon)
The second call to the method (using "largeSquare") also fails:


This is a bit more difficult to understand. The "largeSquare" variable is typed to our interface, IRegularPolygon, and the interface *does* have the "GetPerimeter" method.

But that is not how "dynamic" works here. If we look at the exception, we see that we have the same message that we saw earlier: "GetPerimeter" is not part of "Square".

The Runtime Binder is not looking at the type of the object, it is looking at the object itself. Specifically, it is looking at the visible members of the object. Since the object is a "Square", that is what the Runtime Binder sees.

Bug or Intended?
I'm not sure if this is a bug or if this is how it is intended to work. In looking through the design proposal, I did not see any references to "dynamic". So this may be an oversight.

Or it might be intentional. "dynamic" and the DLR (dynamic language runtime) haven't gotten much love lately. The issues in the GitHub repository for .NET are a bit complicated (and there are a ton of them), so I haven't taken the time to research whether this shows up as an issue in the repository.

Some Error Handling
To avoid runtime exceptions, the final code has some try/catch blocks (in the Program.cs file):


This catches the RuntimeBinderException and shows the message on the console. Here's what that output looks like:


So, we can see that "dynamic" cannot see the default implementation of an interface member.

But then if we keep going, things get a bit more interesting.

Inconsistent Behavior
Understanding how "dynamic" behaves with default implementation is good on the surface, but things get strange if we have some classes that use the default implementation and some classes that override the default.

Here's a Triangle class (from the Triangle.cs file):


Triangle also implements the IRegularPolygon interface. But notice that it provides its own implementation for the "GetPerimeter" method. This overrides the default behavior in the interface itself.

We can create an display the triangle (in the Program.cs file):


And everything works!


This shows that both the "ShowInterfacePolygon" and "ShowDynamicPolygon" methods work with the Triangle class.

The Difference
The difference is that Triangle has its own GetPerimeter method, so the Runtime Binder finds it when using the "dynamic" parameter.

Now this seems a bit dangerous. The "dynamic" method works sometimes but not others.

If a class relies on a default implementation, it fails:


And if a class provides its own implementation, it succeeds.


This is a little bit scary.

Wrap Up
So we need to be a bit careful when using "dynamic" around interfaces that have default implementations for members. If a default implementation is used, then "dynamic" will fail to find it. If the class provides its own implementation, "dynamic" finds it just fine.

The changes in C# 8 make interfaces more complicated than I would like them to be. But digging into them and exploring is how we figure out what works and what doesn't work.

After we have a good handle on the mechanics, we can take a closer look at how to use the new features in a safe and understandable way. But that will have to wait for a future article.

Happy Coding!

Wednesday, September 25, 2019

C# 8 Interfaces: Dangerous Assumptions in Default Implementation

In taking a closer look at C# 8 interfaces, we need to consider that we can make things worse with default implementation.
Making assumptions with default implementation can lead to broken code, runtime exceptions, and slow performance.
One of the features that is being promoted about C# 8 interfaces is that we can add members to an interface without breaking existing implementers. But we can cause a lot of pain if we aren't careful. Let's look at some code that makes bad assumptions so that we can understand the importance of avoiding these problems.

The code for this article is available on GitHub: jeremybytes/interfaces-in-csharp-8, specifically the DangerousAssumptions project.

Note: this article uses C# 8 features, which are currently only implemented in .NET Core 3.0. For these samples, I used Visual Studio 16.3.0 and .NET Core 3.0.100.

Assuming Implementation Details
The main reason I am calling this out is because of a blog article that promotes code that makes really bad assumptions about implementation. (I'm not calling out the specific article because I don't want that blogger to get hammered with comments; I'm going to contact them discretely.)

The article in question is about how good default implementation is because we can add to interfaces after there are existing implementers. However, the code makes some bad assumptions. (This code is in the BadInterface folder of the GitHub project.)

Here is the original interface:


The article continues by showing an implementation of the interface "MyFile" (in the MyFile.cs file):


The article then shows that we can add a "Rename" method with a default implementation that won't break the existing "MyFile" class.

Here is the updated interface (from the IFileHandler.cs file):


MyFile still works so everything's great, right? Not exactly.

Bad Assumptions
The main problem with the "Rename" method is that it makes a *HUGE* assumption: the implementations are using a physical file on the file system.

Let's take a look at an implementation that I created to use an in-memory file system. (Note: this is my code; it is not from the original article. You can see the full implementation in the MemoryStringFileHandler.cs file.)


This class implements a naive file system that uses an in-memory Dictionary to hold text files. There is nothing here that touches the physical file system, and it does not reference System.IO at all.

Broken Implementer
With the update to the interface, this class is now broken.

If client code calls the "Rename" method, it will generate a runtime error (or worse, it will actually rename a file on the file system).

Even if our implementation is using physical files, it may be using files that are located in cloud storage and are not accessible through System.IO.File.

This is also a potential problem when it comes to unit testing. If a fake or mock object is not updated, but the code under test is updated, this will try to touch the file system when the unit tests are run.
Because a bad assumption is made in the interface, implementers of the interface are broken.
Unreasonable Fear?
It's pretty easy to think about this as an unreasonable fear. When I talk about mis-use of code, often the response is "well, that's bad programming." I don't disagree with that.

My general response is to wait and see how things are used. For example, I had a fear that "static using" would be abused. So far, I haven't seen that. But in this instance, there is at least one article out there that is promoting this type of code (and there may be more).

We need to be aware that these ideas are out there so that we can help people move back onto a happier path that won't cause as much pain.

As always, we get better by helping each other out.

Performance Issues
I started thinking about other ways that we could get into trouble when we make assumptions about interface implementers.

The previous example calls code that is outside of the interface itself (specifically, from System.IO). We can probably agree that doing something like that is a danger sign. But if we're using things that are already part of the interface, we should be okay, right?

Not necessarily.

Just as a quick example, I created an "IReader" interface. (This is more thought out than the embarrassing IReader interface that included a "Save" method in a previous article.)

Original Interface & Implementation
Here is the original IReader interface (from the IReader.cs file -- although the file has updates):


This is a generic interface with a method to get a read-only collection of items.

One implementation of this interface generates a Fibonacci Sequence (Yes, I have an unhealthy interest in generating Fibonacci Sequences.) Here is a FibonacciReader (from the FibonacciReader.cs file -- this file also has updates on GitHub):


The FibonacciSequence class is an implementation of IEnumerable<int> (from the FibonacciSequence.cs file). It uses an 32-bit integer as a data-type, so it overflows pretty quickly.


If you're interested in this implementation, take a look at TDDing into a Fibonacci Sequence in C#.

The DangerousAssumptions project is a console application that writes out the results of the FibonacciReader (from the Program.cs file):


And here's the output:


Updated Interface
So, we have working code. But at some point we might want to get an individual item from the IReader rather than getting the entire collection of items. Since we are using a generic type on the interface, and we do not have a natural ID property on the object, we'll pull out an item at a specific index.

Here's our interface with the "GetItemAt" method added (from the final IReader.cs file):


The "GetItemAt" includes a default implementation. At first glance, this doesn't look too bad. It uses an existing member of the interface (GetItems), so it is not making external assumptions. And it uses a LINQ method on the results. I'm a big fan of LINQ, and this code looks reasonable.

Differences in Performance
Since the default implementation calls "GetItems", it requires that the entire collection be returned before a specific item is picked out.

In the case of the FibonacciReader, this means that all of the values are generated. An update to the Program.cs file will show this:


This calls "GetItemAt". Here is the output:


If we set a breakpoint inside the FibonacciSequence.cs file, we can see that the entire sequence is generated for this.


Running the program will hit this breakpoint twice: once for the "GetItems" call and again for the "GetItemAt" call.

Performance Hindering Assumption
The biggest problem with this method is that it requires the entire collection of items to be retrieved. If this "IReader" is going against a database, then all of the items are pulled back so that a single item can be selected. It would be much better to let the database handle this functionality.

With our FibonacciReader, we are calculating each new item. This means that the entire list needs to be calculated in order to pull out the one item that we want. Calculating a Fibonacci sequence is not very CPU-intensive, but what if we were doing something a bit more intensive, like calculating prime numbers.

You might be saying, "Well, there's a 'GetItems' method that returns everything. If that takes so long to do, then it probably shouldn't be there." And that's a fair statement.

But the calling code doesn't know about any of this. If I'm calling "GetItems", I know that I'm going through a (possibly) network and data-intensive process. If I'm asking for a single item, I don't necessarily think that same thing.

Specific Performance Fix
For the FibonacciReader, we can put in our own implementation to get much better performance (in the final FibonacciReader.cs file):


The "GetItemAt" method overrides the default implementation that is provided in the interface.

This uses the same "ElementAt" LINQ method that the default implementation uses. But instead of using that method on the read-only collection that comes back from "GetItems", it uses it on the underlying FibonacciSequence, which is an IEnumerable.

Since the FibonacciSequence is an IEnumerable, calling ElementAt will stop once it gets to the selected item. So rather than generating the entire collection, it only generates items up to that specific index.

To try this out, keep the same breakpoint as above and run the application again. This time, it will only hit the breakpoint once (for the "GetItems" call). It does not hit the breakpoint during the "GetItemAt" call.

A Bit Artificial
This example is a bit artificial because we don't normally pick items out of a dataset by index. But we could think of something similar that would happen if we had a natural ID property.

If we pulled items out by ID rather than index, we could have the same performance issues on a default implementation. The default implementation would require all items to be returned to pick out just one. Letting a database or other "reader" pull out an individual item by ID would be much more efficient.

Think About Your Assumptions
We always make assumptions. If we tried to code for every possible use of our libraries, we would never be done. But we need to think about the assumptions that we do make for our code.

This doesn't necessarily mean that the "GetElementAt" default implementation is a bad one. It does have potential performance issues. But if the data sets are small or the calculated elements are "cheap", then it may be worth the trade.

I'm still not a big fan of changing an interface after it has existing implementers. But I understand that there are scenarios where it is preferable to other options. Programming is all about problem solving, and that includes weighing pros and cons for each tool and technique that we use.

Default implementation has the potential to cause harm to the implementers of the interfaces (and potentially the callers of those implementations). We need to take special care regarding our assumptions when it comes to default implementation.

Happy Coding!

Tuesday, September 24, 2019

C# 8 Interfaces: Properties and Default Implementation

In taking a closer look at C# interfaces, we'll start by exploring default implementation and how it relates to properties. Here's what I've found:
Default implementation is really good for calculated properties; it's not so good for read/write properties.
The code for this article is available on GitHub: jeremybytes/interfaces-in-csharp-8, specifically the InterfaceProperties project.

Note: this article uses C# 8 features, which are currently only implemented in .NET Core 3.0. For these samples, I used Visual Studio 16.3.0 and .NET Core 3.0.100.

Default Get
Let's start by looking at an interface that has a default "get" for a property. Here's an interface that describes a regular polygon and has a default implementation (from the IRegularPolygon.cs file):


This describes a regular polygon -- a geometric shape with 3 or more sides where each side is the same length.

The interface describes four properties. (1) NumberOfSides is a read-only property that tells how many sides the shape has. This is read-only because we do not want type of shape (triangle, square, etc.) to change after it is created.

(2) SideLength is a read/write property. The size of the shape is allowed to change during its lifetime.

(3) Perimeter is the distance around the shape. This is a calculated property. Since the calculation is the same for every shape, we included a default implementation.

This code uses the expression-bodied member syntax to return the number of sides multiplied by the side length. If you're not familiar with expression-bodied members, this is the equivalent of the following code:


The expression-bodied member syntax is a short-hand that removes the braces and the "return" keyword. I'll be using the shorter syntax throughout this article, but they are equivalent in functionality. Read more here: Expression-bodied members - Properties.

(4) Area is the space inside the shape. This is also a calculated property, but the calculation is different from each shape. Because of this, we do not provide a default implementation. It will be up to each class to specify it's own calculation.

A Shorter Default Get
There is a slightly shorter way to specify a default "get" for a property (from the IRegularPolygon.cs file):


This is a shorter version of the expression-bodied member syntax that can be used with read-only properties. In this case, we can get rid of the "get" keyword and the braces around that.

This syntax makes it a bit harder to tell whether this is a property or a method. (The difference is that an expression-bodied method would have empty parentheses after "Perimeter".) Read more here: Expression-bodied members - Read-only properties.

Implementing the Interface
Here is a square that implements this interface (in the SquareFromInterface.cs file):


This class implements the IRegularPolygon interface. It provides automatic properties for NumberOfSides and SideLength, and it has a constructor that initializes those properties. There is also an implementation for the Area property. This uses the same expression-bodied member syntax shown above.

One thing to note is that the Perimeter property is not implemented in this class. It relies on the default implementation provided by the interface.

Using the Class
This project is a console application, and we use this square class in the Program.cs file.


This code creates 2 instances of the SquareFromInterface class and displays the properties to the console. The output is unsurprising:


An important thing to note about this code is that accessing the "Perimeter" property from the ShowInterfacePolygon method works. Since the parameter (polygon) is IRegularPolygon, it uses the default implementation for Perimeter.

The Property is on the Interface Only
In this case, the concrete type, SquareFromInterface, does not have a Perimeter property. The property exists only as part of the interface. We can see this if we try to change the type of the "polygon" parameter to our concrete type:


In this code, the parameter is "SquareFromInterface". This type does not explicitly have the Perimeter property, so the code fails to build. (We can see the red squigglies under "Perimeter" in the code sample above.)

Overriding the Default Implementation
If we wanted to, the SquareFromInterface class could provide its own implementation of Perimeter. If it did provide that implementation, then that is the value that would be used, even if we cast the type to the interface. We'll take a closer look at how this works in a later article when we look at default implementation for methods.

Default Implementation for Read/Write Properties
There are some restrictions on default implementation for properties. When we have both a getter and a setter, we must provide implementations for both get/set or neither.

These examples are not valid (from the IBadInterface.cs file):


The first property has a default implementation for the get, but an abstract set (meaning, the implementing class needs to provide that). This is not allowed.

The second property has an abstract get with default implementation for the set. (The default implementation happens to be an empty method.) This is also not allowed.

For read/write properties, we need to provide default implementation for both get and set or for neither.

Note: when we provide default implementation for neither get nor set, we just end up with a regular abstract interface property like "SideLength" above.

Default Implementation for Set
Now that we've talked a little about read/write properties, the next question is whether default implementation makes sense for a read/write property, specifically how do we come up with a default implementation for "set".

No Automatic Implementation
Something to think about: there is no way for us to create an automatically implemented property (or auto property) as a default implementation. Let's look at this more closely. Here is the code from the SquareFromInterface class that we saw above:


Both NumberOfSides and SideLength are auto properties, meaning the compiler fills in some gaps for us. For example, the SideLength property really means this:


This is a property with a backing field. Since the "get" simply reads the backing field, and the "set" simply sets the backing field, this can be shortened to the auto property syntax that we have above. (As a side note, that is why the field is grayed-out; Visual Studio is telling us we can make this an auto property.)

The problem with automatic properties is that they use a backing field. This is instance data on the class. Interfaces are not allowed to have any instance data, so we cannot have backing fields in the interfaces.

This means that we can *not* create a property in an interface with an implementation that is an automatic property.

What Can We Put in the Setter?
The next question is whether there is anything that we can put into a default setter that would make sense. I'm not sure there is. (If you have any ideas, be sure to share them in the comments.)

Based on auto property syntax, it's tempting to try something like this for the setter (from the IBadInterface.cs file):


Unfortunately, this code compiles. It's tempting because it feels like we can cheat the auto property syntax for the setter. But in reality, it creates a Stack Overflow.

To show this, we implement this bad interface in an empty class (from the BadObject.cs file):


Since this object has no members, it uses the default implementation from the interface.

Here is some code to use that object (from the Program.cs file):


We can create the object with no problems. But if we try to set the BadMember property, bad things happen, specifically we get a Stack Overflow:



This isn't a surprise. When we set the "BadMember" property, it calls the setter which takes the value and uses it to set the "BadMember" property, which calls the setter for the "BadMember" property... You can see the problem.

Now this problem isn't any different from code that isn't using default implementation. If we create a property setter like this in a class, we will get the same Stack Overflow exception. The difference is that it's a bit more tempting to try something like that with default implementation in the interface to try to mimic what we would get from an automatic property.

Do Setters Make Sense?
Based on the fun that we've had here, I've wondered if there is a scenario where a default implementation for a property setter would make sense. So far, I haven't come across one. Be sure to share you ideas of you've got them.

Greenfield Abstract Class
If I was implementing the regular polygon scenario in a greenfield application (meaning, brand-new code), then I would probably use an abstract class. The implementation for the "Perimeter" calculated property would be just the same. But we could get some more safety for the NumberOfSides and SideLength properties.

Just to show the differences, I coded up the same functionality as an abstract class (from the AbstractRegularPolygon.cs file). First the NumberOfSides property:


The setter in this property has a guard clause to make sure that there are at least 3 sides to our polygon.

The SideLength property has a similar guard clause to make sure the length is greater than zero:


The rest of the class has a constructor to set the properties, and declarations for Perimeter and Area that look very similar to the interface:


The main difference is that for the abstract class, we mark Area as "abstract". We don't have to mark Area as "abstract" in the interface because that is the default.

Another Square Implementation
In the sample, we have a square class that inherits from the abstract class (from the SqureFromAbstractClass.cs file):


This class is a bit shorter than the one that implemented the interface. That's because it does not need to provide implementations for NumberOfSides or SideLength -- these come from the base class. The constructor calls the base class constructor with a hard-coded "4" for the number of sides.

Then we have an override of the Area property. This looks the same as our other square class.

Using the Square
The console application has code to use SquareFromAbstractClass (in the Program.cs file):


This code creates 2 instances from the interface class and 2 instances from the abstract class class. There is a different display function for the abstract class:


This is almost the same as the code that displays the interface properties. The only difference is the parameter type.

And we get similar output:


Since the display functions are so similar, it would be nice to combine them. In other samples, I've used "dynamic" to create a shareable method. But I ran into some problems when I tried that here.

Issues with Dynamic and Default Implementation
The regular polygon code is taken from a sample I use when teaching interfaces. For that code, I use a single method that can display multiple unrelated types. (The code is on GitHub if you're interested: DisplayPolygon sample.)

I ran into a problem when I tried that with the code that we have here. Here is a shareable method (from the Program.cs file):


This uses a "dynamic" as a parameter. This means that it is resolved at runtime rather than compile time. The good thing about this is that it will work with any object. And as long as the property or method is available on the object at runtime, everything works fine.

Or it almost works in this case.

Here's the code that calls the method:


But when using the dynamic method with the default property implementation, we get a runtime exception:


This is telling us that the runtime binder cannot find the "Perimeter" property on the "SquareFromInterface" object.

This is true. The "SquareFromInterface" class does not have its own "Perimeter" property. Instead, it relies on the default implementation from the interface.

You might be thinking that we need to pass to cast the object to the interface type before we pass it to the method. Well, it turns out that we did do that:


The "largeSquare" variable that we use is an IRegularPolygon (our interface). But even though we pass that type through, the runtime binder picks up the concrete object.

I don't know if this is a problem with the runtime binder, or whether this is intentional. I'll just leave a warning that when relying on a default implementation of an interface, there may be problems when combining it with "dynamic" objects.

Just as a note: the "dynamic" method works just fine with the abstract class class since "Perimeter" is part of the base class.

Update: I explored this behavior a bit further: C# 8 Interfaces: "dynamic" and Default Implementation.

Wrap Up
There has been a lot to think about. Default implementation seems like it can be really useful for calculated properties, particularly if we need to add a property after the interface is in a production environment.

But when it comes to setters for properties, default implementation doesn't seem to make much sense. And it's easy to get a stack overflow if we include a self-reference in the implementation.

As a reminder, you can get the code (and additional article links) from the GitHub repo: jeremybytes/interfaces-in-csharp-8.

We have a good idea of what the mechanics are for default implementation for properties. In future articles, we'll look at some guidance on default implementation in general.

Happy Coding!