Everything in the .NET framework should be open for extension. Extension, not change. The idea behind this is that you have an existing class that does what it should, and works how it should, and it is not a good idea to change the contents. But if you do want to change something…? And that’s where C# extension methods make an entrance.
Table Of Contents
What Are C# Extension Methods?
If you have existing types in C# and you want to expand them with new functionality, you can create an extension on the type. This is recommended when you have existing types that work in a production environment and changing them could cause errors or worse.
Another scenario could be that you are using third-party types (NuGet packages or DLLs from other companies/teams) and you want to extend them.
You add methods to the types without changing the type. This also means you don’t have to recompile the base type. We could, for example, make an extension on the type string. Look at the code below.
string title = "Some title that should be shown # in an URL?"; title = title .Replace(" ", "_") .Replace("?", string.Empty) .Replace("#", string.Empty) .ToLower(); Uri uri = new($"https://kenslearningcurve.com/{title}");
The title is a parameter that is being used in a URL, but it contains characters that aren’t allowed in a URL. So on line 3, I made some code that removes those characters and makes everything lowercase. Although this code is correct, it’s not a good idea.
Imagine you have another class that needs to do the same thing and make a string URI proof. You could copy-paste the code above, but this would cause a duplicate code violation or the DRY principle. Also, what if you need to add another replacement to the title? Your code could be a mess if you are not careful.
Creating C# Extension Methods
Let’s create reusable C# extension methods for the problem above.
First off, extension methods are static. This means they are accessible without initializing them or the type. They are also easy to use and find. Keep this in mind when you create them. Most people don’t get why extension methods are not found until they see it’s not static.
Some of the following steps are personal ideas on how to approach extension methods. The content of such a method is the same.
First, I create a new folder in a logical place. Could be in your application itself, or a business layer. Maybe you can create a whole new project for your extensions. Just don’t do this if you just have a few. I call this folder ExtensionMethods. This way I know what’s inside that folder.
Preparing The Extention
Next, I create a new class for the extension method. I usually call this NameOfTheTypeExtensions. This is how I know what kind of extensions this class will contain. Since I want to create an extension on a string I call the class StringExtensions. I now have an empty class.
internal class StringExtensions { }
As I said before, extension methods are static. So I make this class public and static.
Give The Extension Logic
Now it’s time to create the method itself. I call this method MakeUriFriendly. There is no need to add string or anything to the name. This method should be static as well. Since I expect a string the method will get a return type of string. It gets one parameter, which is the type the method operates on (string in this case). The code would look like this:
public static class StringExtensions { public static string MakeUriFriendly(this string value) { } }
Time to add the body of the MakeUriFriendly method. This one is easy: Copy the code from the first code (title.Replace… and stuff) and paste it into the extension method. Make sure to change the variable name from title to value (or value to title). I would keep value since you have no idea what value is. Could be a title, a name, or a brand…
public static class StringExtensions { public static string MakeUriFriendly(this string value) { return value .Replace(" ", "_") .Replace("?", string.Empty) .Replace("#", string.Empty) .ToLower(); } }
Almost there. The only thing we need to do is change the original code to use the extension method.
string title = "Some title that should be shown # in an URL?"; title = title.MakeUriFriendly(); Uri uri = new($"https://kenslearningcurve.com/{title}");
Make sure you use the correct using and you’re done!
The code could be nicer though:
string title = "Some title that should be shown # in an URL?"; Uri uri = new($"https://kenslearningcurve.com/{title.MakeUriFriendly()}");
Unit Testing C# Extension Methods
As with most of our code, we should unit-test it. C# extension methods are really easy to test. You can access them from the unit test and check if they work as they should. Let’s take the extension method from above and make a unit test.
While creating the unit test I noticed I didn’t check what would happen if the value in the extension method is NULL or empty. So I have added that and changed the extension method:
public static class StringExtensions { public static string MakeUriFriendly(this string value) { if(string.IsNullOrEmpty(value)) return null; return value .Replace(" ", "_") .Replace("?", string.Empty) .Replace("#", string.Empty) .ToLower(); } }
public class StringExtensionsTests { [Fact] public void Should_ReturnValidString() { // Arrange string input = "Some title that should be shown # in an URL?"; string expected = "some_title_that_should_be_shown__in_an_url"; // Act string result = input.MakeUriFriendly(); // Assert Assert.Equal(expected, result); } [Theory] [InlineData("", null)] [InlineData(null, null)] public void Should_ReturnNull_When_ValueIsInvalid(string input, string expected) { // Act string result = input.MakeUriFriendly(); // Assert Assert.Equal(expected, result); } }
Conclusion On C# Extension Methods
C# extension methods are convenient if you want to reuse existing code in different ways. If something needs to change (replace a ! with string.Empty for example), I just need to change the extension method and not search through my code to add the replace to all other occurrences.
As you can see, C# extension methods are fairly easy to create. Just don’t go berserk on them. Use them with care and only when you notice you have a duplicate code violation or when your code becomes really hard to understand. It is also a good idea to create unit tests for the extension methods to make sure they always work as you intended.