Tuesday, December 17, 2019

C# 8 Interfaces: Static Main -- Why Not?

When taking a closer look at C# 8 interfaces, we come across static members. Last time we looked at using static fields and methods in an interface. But things get stranger. An interface can have a "static Main" method, which means that this is a valid application:

Okay, so there's technically more to it than this, but still: Yikes!
A static Main method lets us put the entry point to an application in an interface.
Let's take a look at this example to see what it means.

The code for this article is available on GitHub: jeremybytes/interfaces-in-csharp-8. Specifically, this uses the "StaticMain" project.

Note: this article uses C# 8 features which are not available in .NET Framework 4.8. For these samples, I used Visual Studio 16.4.1 and .NET Core 3.1.100.

Static Main
The static Main method is the entry point to an application. In a C# console application, this is generally in the "Program" class. And if you create a new console application using the .NET Core template, you get the following code:

Personal Note: One really sad thing about this template is that it fills in the "Hello World!" for you. So this takes all the fun out of building your first application.

The same is true of ASP.NET Core web applications and APIs. Here's the "Program" class that was created using the "webapi" template:

There is a bit more to the "Program" class than what is seen here, but the "Main" method is the entry point. When we start up the application, it runs "Main".

Static Main in an Interface
With C# 8 we can have static members in an interface. We can also create a "static Main" method in an interface.

Here is an interface that has a static Main method: "IHelloWorld" (from the IHelloWorld.cs file in the StaticMain project on GitHub):

The "Main" method has the same signature as the prior samples from a console application and an API application.

But instead of this method being in the Program class, it is in an interface.

The Shortest Program Class
When we have an interface with a static Main method, it leads to the world's shortest Program class (from the Program.cs file):

This is a valid C# console application (and it actually does something).

Running the Application
Let's see it work. From the command line (open at the project folder), we can type "dotnet run" to run the application.

And if we pass in a command line argument, we see that also works.

Note: When running a console application (or other application) with "dotnet run", we can pass arguments through by adding 2 dashes (--). Everything after those 2 dashes will show up in the "args" parameter on the "Main" method.

So we have a working application that has an empty body for the "Program" class.

"Program" is not Needed
So the "Program" class is empty, and it isn't doing any thing. Do we need it?

No, we don't.

If we remove the "Program" class entirely, the console application still works. That is because the "static Main" method is the entry point to the application; the "Program" class is not the entry point. The "Program" class is used as a convention, but we can use a different class (or interface) as the entry point to the application.
Developers expect to see the entry point inside the Program class. 
Keep that in mind if you are considering something different.

Multiple Entry Points
If we create another interface that has a "static Main" method, we get a compiler error. Here's the message:

"Program has more than one entry point defined. Compile with /main to specify the type that contains the entry point."

This restriction is not new; we've always had this if we tried to define multiple entry points. The difference is that it can apply to interfaces now, too.

This also means that if we have a "static Main" in the Program class, we cannot also have one in an interface (unless we use the compiler switch mentioned in the error message, and that's beyond the scope of this article).

Sure. Why Not?
As mentioned in previous articles (Static Members and Public, Private, and Protected Members), I'm still processing these changes and how they should influence my code.

Right now, I'm still holding onto the idea that interfaces are abstractions. But when we're talking about static members, we really lose that. So if we're talking about putting the entry point of an application into an interface... Why not?

Unfortunately, that is the design decision that came from Microsoft. If you check the Language Design Notes from Oct 17, 2018 (https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#main-in-an-interface), you'll find this gem:

"Main in an interface? No reason why not."

Translation: "No point in steering now."

Just Because You Can...
Just because you can do something doesn't mean that you should do something. I'm pretty hard-pressed to come up with a scenario where the entry point of an application would need to come from an interface. (I'll just brace for everyone supplying me with edge-case examples.)

The deeper I get into the changes to interfaces, the more concerned I get. I think that we've lost the meaning for what an interface is.

But there is nothing that forces us to use these features. So if we make the decision, we can continue to use interfaces as abstractions in our code. Even if we do this, it's important to understand what is possible because we may end up using libraries that *do* use these new features. I'm still hoping for the best at this point.

Happy Coding!

Sunday, December 15, 2019

C# 8 Interfaces: Static Members

When taking a closer look at C# 8 interfaces, we have a new capability: interfaces can have static members (including static fields).
Static members give us the ability to run code from an interface without an instance of that interface.
This functionality is similar to how static members work in classes. Let's take a look at an example to show what we can and can't do with static interface members.

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

Note: this article uses C# 8 features which are not available in .NET Framework 4.8. For these samples, I used Visual Studio 16.4.1 and .NET Core 3.1.100.

When we create a static member on a class, we can use that method without creating an instance of that class.

Here's an example that takes the square root of a number and then outputs it to the console along with the current time:

This "Sqrt" (square root) method is a static method on the Math class. So we can take the square root of a number without creating an instance of the Math class.

The same is true of "Console.Writeline" and "DateTime.Now" (although DateTime is a struct rather than a class).

We won't get into whether using "static" is a good idea or not. Static members cause particular difficulty when unit testing. For a look at a workaround that is necessary when using "DateTime.Now" take a look at this article: "Mocking Current Time with a Simple Time Provider".

Today we will look at the mechanics of what is possible by using static members.

An Interface with Static Members
The code for this sample is in the StaticMembers project on GitHub. For this sample, we have a static factory that will return us a data reader.

Here is a summary of the code for the interface (from the IReaderFactory.cs file in the StaticMembers project):

We'll look at the details of what this does in a moment. For now, we'll note that  our interface has 3 members: a private static field, a public static field, and a public static method.
Static Methods on an interface *must* have an implementation. 
Static Fields do not need to be initialized by default (but it's probably a good idea).
Just like with static members on classes, we can call these members without an instance:

The first line sets the "readerType" field, and the second line calls the "GetReader" method. These all happen without having an implementation/instance of the "IReaderFactory" interface.

We'll dig into the details of this in a bit. Let's take a look at the application at large and then dive into the interface members and calling code.

Project Overview
The project is a console application. Here is the project in the solution explorer:

The "DataReaders" folder has the code for the data readers that the factory will create.

The "Factories" folder has the interface that we saw above (as well as a class-based implementation).

The "People.txt" file contains data that is used by one of the readers, and "Program.cs" is the console application itself.

As with most samples, this code is highly simplified. This factory-based approach is a bit complex for a single-project console application. I'd be more likely to use something like this if I had multiple projects and needed to do some type of dynamic loading of dependencies. But we'll take this code "as is" to look at the technical capabilities.

Let's start by touring the data readers.

Data Reader Interface and Implementation
In the "DataReaders" folder, we have an "IPeopleReader" interface. Here's the code for that (from the IPeopleReader.cs file):

This interface has 2 methods. The first gets a collection of "Person" objects, and the second gets an single "Person" based on an identifier. The "Person" class is defined in the "Person.cs" file. It contains a collection of read-write properties and an override of the ToString method. You can check the file in the GitHub project if you'd like details.

We have 2 implementations of this interface. The first is "HardCodedPeopleReader" (from the HardCodedPeopleReader.cs file):

This class implements the "IPeopleReader" interface, so it has the 2 methods. The "GetPeople" method returns a hard-coded list of Person objects. You can check the file on GitHub if you'd like the details.

The second implementation is "CSVPeopleReader" (from the CSVPeopleReader.cs file):

This class also implements "IPeopleReader". But it gets data from a text file in comma-separate values (CSV) format. (This is the "People.txt" file at the root of the project.)

The code is a bit more complex since it is loading and parsing data from the file system. Again, you can check out the GitHub project if you're curious about specific implementation.

The Factory Interface
So let's go back to the factory interface: "IReaderFactory". Here is the detail code (from the IReaderFactory.cs file):

The overall idea of this factory is that "GetReader" will give us a data reader instance based on the "readerType" field. The "savedReader" field will hold the instance so that the data reader is not re-created each time.

The "readerType" public static field contains the type for the data reader we want to use. It is defaulted to the "HardCodedPeopleReader" that we saw above.

Initialization and Implemetation
As noted above, the static fields do *not* need to be initialized. Here we have initialized one but not the other. However, the static method *must* have an implementation.

These requirements make sense if we think about them. A public static field can be set from outside of the interface code (we'll see exactly that below). A private static field can be set from somewhere inside the interface.

But a static method cannot be implemented from outside the interface since it is part of the interface itself. So static methods must have an implementation supplied when they are declared in the interface.

Note: it looks like it's possible to have an external implementation, but we won't get into that here; "extern" has its own set of concerns.

The GetReader Method
Let's walk through the "GetReader" method to see how it works.

First, the "if" statement will check to see if the value stored in the "savedReader" private static field has the same type as the "readerType" public static field. If it matches, then the method will return what is in the saved data reader field.

If the "savedReader" value does not match (or is empty), then then a little bit of reflection is used ("Activator.CreateInstance") to create an instance of the type from the "readerType" static field.

If "CreateInstance" is not able to create an instance (for example, if the constructor requires a parameter), then this will throw an exception that we let bubble up.

After the instance is created, we cast it to "IPeopleReader" using the "as" operator. If the cast is unsuccessful, this does not throw an exception. Instead, it returns null.

The result is assigned to the "savedReader" private static field. This will either have a valid "IPeopleReader" or a "null".

Next we do a null check. If the "savedReader" field is null, then we throw an InvalidOperationException that provides the type of the reader and notes that it does not implement the correct interface.

If we get to the last line of the method, then the "savedReader" private static field should have a valid value. So the last step is to return that value.

This gives us a method that will either return a valid "IPeopleReader" instance or throw an exception.

Calling Static Members
Calling static members on an interface works just like calling static members of a class. The code in the "Program.cs" file is a console application that uses the factory.

Here is the "DisplayPeople" method from the Program.cs file:

The first line uses the static "GetPeople" method on the "IReaderFactory" interface. Since this is a static member, we do not need an instance of an implementation of the interface.

The rest of the method uses the data reader that is returned from the static method: (1) printing the type to the console, (2) calling "GetPeople" on the data reader, (3) displaying the resulting collection, (4) printing any exceptions to the console.

The "DisplayPeople" method is used in the "Main" method of the program (also from the Program.cs file):

The first section calls "DisplayPeople" and will use the default data reader (i.e., "HardCodedPeopleReader"). Here are the results from that first section:

The next section sets the "readerType" public static field to use "CSVPeopleReader". Note that since "readerType" is a "Type", we need to use "typeof()" to get the proper value for the field.

After setting the "readerType", calling "DisplayPeople" again gives us different results:

This data comes from the "People.txt" file and has an extra record ("Jeremy Awesome").

The last section sets the "readerType" field to an invalid value ("Person"). This will trigger the exception handling code:

A Note about Static Fields
This interface has 2 static fields, one public and one private. This is a significant change to interfaces. In C# 7 (and before), interfaces could only contain properties, methods, events, and indexers -- fields were *not* allowed.

The reason for the exclusion of fields is that they hold data that belongs to a particular instance. Something similar could be said for constructors and destructors -- these are implementation details that do not belong to the abstraction.

But *static* fields are different. A static field does *not* belong to an instance. This is not instance-related data; this is data that belongs to the interface itself. This also means that there is only one value for a field. If we have 2 classes that implement an interface with a static field, both classes share that value (more accurately, they share access to a single value).

If the static field is public and assignable, that means that anything can change that value -- including implementing classes or code that has nothing to do with implementation (like in our console application).

Because of the possibility of assignment from multiple sources, we need to be very careful about using public static fields. The value could be changed out from under us at any time. This would lead to unexpected behavior.

Static Fields as Parameters
This sample shows how a static field can be used as a parameter for other members of the interface. These parameters do not need to be restricted to static methods; instance methods can use them as well.

Static fields can be used to parameterize default implementations for non-static members. The Microsoft docs site has a tutorial that shows this: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/default-interface-methods-versions#provide-parameterization.

I'll have to admit that I'm not a huge fan of the example shown in the prior link -- primarily because this code is complex enough to step pretty far outside the bounds of what we have traditionally called an "interface". This is something that I mentioned in a prior article (C# 8 Interfaces: Public, Private, and Protected Members), specifically when looking at private members.

This view is still subject to change. On one side, there are people who are pushing for interfaces as abstractions, and on the other side, there are people who are pushing for interfaces as implementation. I'm not sure where we'll end up (or where I'll specifically end up). We need to have discussions about how to take things forward in a way that most developers can be successful.

The Same Thing with a Class
All of the static member functionality that we've seen in this example can be accomplished with a class. The sample project contains a class that does just that: ReaderFactory.

Here is the code from the ReaderFactory.cs file:

The body of the class is identical to the body of the interface that we saw above. And the console application can be updated to use this class instead of the interface, and it will operate just the same.

Class or Interface?
As mentioned above, we won't get into the pros and cons of static members in this article. We are just looking at what is technically available to us.

Since the code shown here includes only static members, I would probably lean toward a class for this particular code. If there were closely-related abstract members, then I might lean toward an interface (or maybe just an abstract class).

For now, I'm exploring what is possible with interfaces in C# 8. But I'm still thinking of interfaces as abstractions (for now).

Wrap Up
Static members in interfaces are quite a change from C# 7:
  • Interfaces can have static members
  • Static methods must have implementation
  • Static fields are now allowed
  • Static fields do not need a default value (but probably should have one)
  • Static fields can be used to provide parameters for other members
There are a lot of changes to interfaces in C# 8. Even with "static" there is more to explore. For example, it is possible to create static constructors in an interface. I still need to take a closer look at what this means and why we might need to do that.

Keep exploring, keep learning. Once we get the technical details down, we can start trying new techniques to see where they lead us.

Happy Coding!

Tuesday, November 26, 2019

Tutorial: Get Comfortable with .NET Core and the CLI

The Short Version
I've created a walkthrough to get started using .NET Core and the command-line interface (CLI). It's available on GitHub:
github.com/jeremybytes/core-cli: DemoWalkthrough.md
This is based on a presentation that I've given a couple of times this year.

Update Jul 2021: A .NET 5 version of this walkthrough is also available: https://github.com/jeremybytes/dotnet50-cli.

The Longer Version
.NET Core is the future of .NET. If you come from a .NET background, you're used to using .NET Framework with Visual Studio. .NET Core has some differences that are worth getting to know.

.NET Core has a big emphasis on using a command-line interface (CLI). A primary reason for this is its cross-platform nature. Using the CLI and Visual Studio Code, we can write .NET applications using the same development environment on Windows, Linux, and MacOS.

Even if you're strictly a Windows developer, it's good to understand the command line so that you can use the visual tools more effectively. I find myself switching among Visual Studio 2019, the command line, and Visual Studio Code depending on what I'm doing. By understanding the command-line tools, we can pick the best/easiest option for what we're doing at the time.

This walkthrough will get you started with .NET Core and get you ready to dive deeper into the environment.


Target Audience
The .NET developer who has been using .NET Framework with Visual Studio.

If you have been wondering about .NET Core and how the environment differs from the .NET Framework that you've been using, then you'll get lots of good info and tips from this.

If you've been using .NET Core on a regular basis, you won't get as much out of it.

Get comfortable using .NET Core from the command line.
  • Create new projects (web service, unit tests, console application).
  • Run a web service in a self-hosted environment.
  • Add a reference to another project.
  • Run unit tests.
  • Add a NuGet package.
  • Create a solution and add projects.
Along the way, we'll also see how the project system differs in .NET Core compared to .NET Framework. We'll also use the built-in dependency injection that comes with ASP.NET Core.

The full repository with the completed sample code can be found here: https://github.com/jeremybytes/core-cli-30.

The walkthrough is at the root level of the project in the Walkthrough.md file.

The Walkthrough is a Markdown (.md) file. If you do not already have a favorite Markdown viewer, you can just look at it directly on the GitHub site.

Here's a few screenshots of what you'll find along the way.

Running the Service:

Output from the Service:

Running Unit Tests:

Test Results (with a failing test):

Running the Console Application that calls the Service:

Using Dependency Injection on the API Controller:

Check It Out
If this sounds interesting, be sure to take a look:
Walkthrough: Get Comfortable with .NET Core and the CLI
Happy Coding!

Saturday, November 9, 2019

C# 8 Interfaces: Public, Private, and Protected Members

When taking a closer look at C# 8 interfaces, we come across an interesting change: interface members can have access modifiers - public, private, and protected (and others).
Public members are what we are used to. Private members are useful for refactoring default implementations. Protected members may be useful for interface inheritance (but not much else).
Let's take a look at a few examples to show what we can and can't do with access modifiers and interface members.

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.6 and .NET Core 3.0.100.

Public Interface Members
Prior to C# 8, interface members were public by default. In fact, if you put an access modifier on an interface member (including public), it would generate a compiler error.

The code for this section is available in the "Public" folder of the "AccessModifiers" project on GitHub.

Interface Members Default to "public"
In C# 8, interface members are still public by default. But since other access modifiers are allowed (as we'll see in a bit), public is also allowed.

In the following code, both of the interface members are "public" (from the ICustomerReader.cs file on the AccessModifiers project).

Both the "GetCustomers" method and the "GetCustumer" method are public. So whether we use the "public" keyword or no access modifier, the members of an interface are public.

Class Members Default to "private"
Classes in C# behave differently. Class members default to "private". Here is a sample of a "Customer" class with private members (from the Customer.cs file):

This class has 2 private fields: _familyName and _givenName. Neither of these fields are accessible outside of the class.

The main reason to point this out is that default access is different for interface members (public) and class members (private).
As a practice going forward, I will use "public" explicitly in my interfaces to reduce confusion.
Implementation Still Needs to be Marked "public"
Something important to note is that even though the interface members default to public, they still need to be explicitly marked as "public" in the implementation code.

Here is a snippet of the "FakeCustomerReader" class that implements the "ICustomerReader" interface that we saw above (from the FakeCustomerReader.cs file):

This code provides implementations for the "GetCustomer" and "GetCustomers" methods from the interface. But they both must be marked as "public" for the code to compile.

Even though "GetCustomers" does not have an access modifier in the interface (public default), it does require an access modifier in the implementation since classes default to private.

This is no different from interface implementations prior to C# 8. Even though interface members did not have access modifiers, the implementations required "public" implementation (unless they were explicit implementations -- we'll talk a little about explicit implementation further down).

Private Interface Members
Something new in C# 8 is that we can now have private interface members. Let's work through the why and how of private members by looking at some code.

The code for this section is available in the "Private" folder of the "AccessModifiers" project on GitHub.

Private Members Must Have Default Implementation
By definition, private members are not accessible outside of the current object. In our case, this means that a private interface member is not accessible from outside of the interface.

Consequently, there is no way to provide an implementation for a private interface member outside of the interface.

Fortunately, the compiler knows about this. The following code is not allowed (from the ICalendarItem.cs file):

In this code, we try to create a private read-only property for the interface.

Here is the error message:

This tells us that we *must* declare a body (i.e., a default implementation) for this member. (Note: we won't get into the "abstract, extern, or partial" in this article. We'll look at those in future articles.)

So to make our code happy, we must provide a default implementation (from the ICalendarItem.cs file):

This adds a default implementation to the "DefaultType" property.

As a side note, "CalendarItemType" is an enum defined in the ICalendarItem.cs file.

Private Members are Useful for Other Default Implementations
Since private members are not accessible from outside of the interface itself, they are really only useful for default implementations of other interface members.

Here's an overly-simplified example (from the ICalendarItem.cs file):

Here we have another interface member: a public property called "ItemType". This has a default implementation that uses the private "DefaultType" property.

Again, this is an overly-simplified example. The primary purpose that I've seen for using private members on interfaces is to extract methods and refactor code to smaller pieces.

Here's the problem that I have with those examples: if the code in the interface implementation is so large that we feel the need to refactor, then is this really an interface? At some point we will need to decide whether we keep interfaces as abstractions or turn them into active code files.

In my current opinion (which is subject to change), if we add too much code to interfaces, then they are no longer "interfaces". I really wish that these new features were added under a new name or syntax. At some point the word "interface" becomes meaningless. But that's a discussion for another time.

Private Interface Properties are Read-Only
In thinking about private members, we should consider what we learned about properties and default implementation. In a previous article (Properties and Default Implementation), we saw that default implementation does not make sense for read-write properties. It is good for calculated or constant read-only properties.

Since private interface members must have default implementation, we can extend this to mean that private interface properties should also be read-only.

This isn't really ground-breaking, just another thought that came up while I was exploring code.

Private Interface Members are not Accessible by Implementing Classes
As stated above, private interface members are not accessible from outside of the interface itself. This means that an implementing class cannot access private members (which should not be a surprise).

Just to show this, here is some code from a "CalendarEvent" class that tries to access the private member (from the CalendarEvent.cs file):

This code tries to assign to the private "DefaultType" member of the interface.

The error message tells us that "DefaultType does not exist in the current context."

This is the same message that we would get when trying to access a private member on any other type.

Protected Interface Members
The last thing that we'll look at today is protected interface members. This is the strangest (and probably least useful) of the access modifiers here.

The code for this section is available in the "Protected" folder of the "AccessModifiers" project on GitHub.

I'm not sure how this works completely. So the examples here are from my experimentation. In the language proposal for default interface methods, the issue is left open:

"Open Issue: We need to specify the precise meaning of the access modifiers such as protected and internal, and which declarations do and do not override them (in a derived interface) or implement them (in a class that implements the interface)."

There may be a GitHub issue that resolves this; however, I haven't had any luck finding one so far. Here's what I've found through experimentation.

Protected Interface Members are Allowed
As an experiment, I created an interface that has a protected member (from the IInventoryController.cs file):

This interface has 2 members: a public "PushInventoryItem" method and a protected "PullInventoryItem" method.

Protected Interface Members *Must* be Implemented Explicitly
The next thing I found is that protected interface members must be implemented explicitly.

If we try to implement a protected member "normally", we get an error. Here's code for a "FakeInventoryController" (from the FakeInventoryController.cs file):

This has implementations for both the public member and the protected member, but the red squigglies under the interface name tell us that something is wrong.

The error message tells us that we have an incomplete implementation of the interface: "FakeInventoryController does not implement interface member PullInventoryItem".

Changing the access modifier on the affected item does not change anything. The only way to satisfy the interface is to implement the interface member explicitly.

Here is the explicit implementation (from the FakeInventoryController.cs file):

With explicit implementation, we do not provide an access modifier on the implementation. In addition, the declaration "IInventoryController.PullInventoryItem" specifies that this code can only be called using the explicit interface type. (We'll see this in just a bit.)

To show the differences between the public and protected members of the interface, the final code shows both interface members implemented explicitly (from the FakeInventoryController.cs file):

This code compiles without errors.

There is No Way to Access the Protected Interface Implementation
This is where things get really strange. We have an interface with a protected member (this compiles fine). We have a class that explicitly implements that interface (this compiles fine). But we can *not* access the protected implementation.

The root of the AccessModifiers project on GitHub has a Program.cs file to test this.

This code creates an instance of the "FakeInventoryController" class and assigns it to an "IInventoryController" variable.

Note that it is important that the variable is the interface type. When using explicit implementation, we can only access the interface members through the interface type. (For more information on explicit implementation, take a look at this article: Explicit Interface Implementation.)

When we access the "PushInventoryItem" method (the public interface member), everything works as expected.

But when we access the "PullInventoryItem" method (the protected interface member), we get a compiler error.

The error tells us that "PullInventoryItem is inaccessible due to its protection level". So even though we have access to the member through the class (and the explicit implementation), we cannot call that implementation. This is true even though we are using the interface as the type.

Using Protected Interface Members
If we can't use protected interface members, then what are they there for? As noted in the "Open Issue" that we saw above, protected members may be useful when we have interface hierarchies (meaning, one interface inherits from another interface).

I haven't done any experiments with this because I try to keep things simple. I do use interface inheritance, but I do this to compose interfaces and add new members. I do not do this to try to override base behavior or get into polymorphism. I've generally found that if you try to be to clever with polymorphism and determine which method gets called depending on the situation, it's very difficult for the humans to follow along.

So I'll leave this as an exercise for the reader.

Broken Tooling with Protected Members
Visual Studio tooling is generally really awesome, but the current tooling breaks down with protected interface members (at least with Visual Studio 2019 16.3.6).

I love to use the Quick Actions in Visual Studio (particularly to implement interfaces). You get to this by clicking the lightbulb icon or by using "Ctrl+." with the cursor on the interface.

When implementing an interface with these tools, the explicit implementation works just fine:

Using "Implement interface explicitly" generates both methods as explicit implementations (which is what we have in the final code).

But if we try to use "Implement interface" (the non-explicit version), we run into problems:

This only generates implementation for one of the members (the public one).

And as we saw earlier, this leads to an incomplete implementation:

Note the red squigglies that we saw earlier. This is because we do not have an implementation for the protected member.

The reason that I'm a bit disappointed by this is because Visual Studio has been really smart with implementations in the past. For example, if there were conflicting interface members (meaning 2 interfaces with the same method name and parameters, but different return types), Visual Studio would implement the conflicting members explicitly (even if you asked for the non-explicit implementation).

I'm hoping that this will be fixed in a future update.

Wrap Up
Interfaces in C# 8 have changed significantly. Adding access modifiers creates a lot of interesting things to thing about.

"Public" is still the default, and this is what we should use most of the time. As mentioned, I've started explicitly using the "public" keyword to reduce confusion.

"Private" is useful for members that will be used for other default implementations. This is a way to break up the code into smaller pieces. (As noted above, whether our interfaces should get this complex is something to consider.)

"Protected" is there, but not very useful. It may be useful in interface hierarchies, but it cannot be used directly through explicit implementation.

There's lots to think about. To get the code and links to other articles, be sure to visit the GitHub repo: https://github.com/jeremybytes/interfaces-in-csharp-8.

Happy Coding!