Recently I’ve been working my way through @KevinDockx‘s excellent PluralSight course on Building a RESTful API in ASP.NET Core. First and foremost, i recommend @KevinDockx‘s courses on plural sight. His courses are well organized and come with excellent source examples.  Kevin’s course have taught me a lot, and I will be reviewing other cool concepts I’ve learned from him.  For this post, I’m going to focus demonstrating an extension method.

As Developers, our goal should always be well factored code.  Ideally, our code is logical and maintains well defined areas of concern.  In reality, it can be difficult to tell where functionality should be placed. Extension methods gives us another tool to help organize our code  Extension methods allow us to append new functionality to existing objects.  Frankly, extension methods are just… cool.

Problem

We want to build a console application that will output text from a text document.  Each line of output will be limited to 60 characters..  All I need is for an application to read text, to split the text, and to output the text.  The text document will have a single continuous line with generic made up text.  All glory to lipsum.  I used the site’s generator to build a sampleText document.  The linked document is what we want to display as wrapped text.

Maybe, this is a trivial problem. A solution could be written that does not use any additional methods or classes beyond the Main method in the Program class.  Except, maintains a separation of concerns.  Specifically, this example is going to execute three broad tasks.  First, it will read a stream file.  Second, it split up a the imported text string.  Finally the program will output distinct text lines.

Reading a stream file and outputting to console are both I/O related tasks.  These tasks share and area of concern.  Similarly, the task of splitting the text sting is its own area of concern.  We will build a word wrap method. However, we do not really need a whole new type to implement a “word-wrap” method.  Instead we will attach the method to a type that shares the new method’s area of concern.  To that end, we will attach the word wrap method to the string type.

Solution

Before We Begin

If you do not have .Net Core’s CLI installed or Visual Studio Code, check out their links and snag yourself a copy.  You’ll need both.  If you are familiar with the dotnet cli, please feel free to skip the next couple of sections.   ((Skip))

Building the project.

The first thing we are going to do is build a new console project.  We are not doing anything fancy, so all we need is the most basic console project there is.  I recommend having a directory to hold example and test code.  I have created a directory, Examples, for this purpose.

Navigate to Examples directory

cd ~/source/Examples

Create a New Console Project.

There are dozens of options for the dotnet new command, and I recommend taking a look at the dotnet new documentation. The command bellow will create a new project, Examples.ExtensionMethod in a folder with the same name.

dotnet new console –n Examples.ExtensionMethod

You should see output similar to this.

The template "Console Application" was created successfully.

Processing post-creation actions...
Running 'dotnet restore' on Examples.ExtensionMethod/Examples.ExtensionMethod.csproj...
  Restoring packages for ~/source/Examples/Examples.ExtensionMethod/Examples.ExtensionMethod.csproj...
  Generating MSBuild file ~/source/Examples/Examples.ExtensionMethod/obj/Examples.ExtensionMethod.csproj.nuget.g.props.
  Generating MSBuild file ~/source/Examples/Examples.ExtensionMethod/obj/Examples.ExtensionMethod.csproj.nuget.g.targets.
  Restore completed in 183.88 ms for ~/source/Examples/Examples.ExtensionMethod/Examples.ExtensionMethod.csproj.

If you explore the newly created directory you’ll find the most basic of .net core applications, effectively only a Program.cs object.

Open the project folder in VS Code

VS Code’s display and navigation is based on folders, not solutions and projects.  So if you are coming from older Visual Studio environments, that might be a little weird.  To access the newly created project, we are going to open it’s containing folder, and not the project file itself.

Importing The Text

Adding user interaction

The first thing we will add is a simple user input to the Main procedure in the program class.  Add a line to the output telling the user to press any key to continue.  Then add a “readkey” to halt the application until the user presses a key.

This is not strictly necessary, but i always like to control when an application ends. The program class should now look something like this.

using System;

namespace Examples.ExtensionMethod
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("\nHellow World!");
            Console.WriteLine("\n\nPress any key to contine.");
            Console.ReadLine();
        }
    }
}

Before we continue, You may need to change generated launch.json document.  In order to test an interactive console application in Visual studio, you have to point the debugger at a terminal.  By default, Visual studio’s debugger points at the internal console, which does not accept input.  Go ahead and open up the launch.json object.  Then change the “console” value from “internalConsole” to either “integratedTerminal” or “externalTerminal”.  In this case, I used the externalTerminal for this simple program.

"console": "internalConsole",
Add Stream File

Now we need to actually read the text file and load it’s contents into a string.  We will need the System.IO library to handle the text document.  Start by adding a using statement for the System.IO library.  Then create a new file stream and stream reader object.  Lastly, create a variable to hold the output of the stream reader.  This post is not intended to review file streams.  So, If you have questions about how to implement a file stream, check out this Stack Overflow page or Microsoft’s documentation. The end result should look something like this.

using System;
using System.IO;

namespace Examples.ExtensionMethod
{
    class Program
    {
        static void Main(string[] args)
        {
            FileStream fileStream = new FileStream("sampleText.txt", FileMode.Open);
            using (StreamReader reader = new StreamReader(fileStream))
            {
                var line = reader.ReadLine();
            }
            Console.WriteLine("\nHellow World!");
            Console.WriteLine("\n\nPress any key to contine.");
            Console.ReadLine();
        }
    }
}

Place a break point on “var line = reader.ReadLine();” and run the application.  The text document’s line is loaded into string “line”.

Add The Text Split Logic

Now we build the logic to split the text and wrap it for us.  The logic is straight forward.  For now we will put this logic in the Main method of the Program class. First create a List<string> to hold the wrapped text.  Then use the .split() string method to break up the text when there is a space.  After you’ve slit the input string, you will need to build up new strings.  Use a for-each loop to iterate through the split text, building stings under 60 characters long.   The strings should be added to the List<string> object.

using System;
using System.Collections.Generic;
using System.IO;

namespace Examples.ExtensionMethod
{
    class Program
    {
        static void Main(string[] args)
        {
            FileStream fileStream = new FileStream("sampleText.txt", FileMode.Open);
            using (StreamReader reader = new StreamReader(fileStream))
            {
                var line = reader.ReadLine();

                List<string> wrappedText = new List<string>();

                string[] splitText = line.Split(' ');

                var buildstring = String.Empty;
                foreach (var text in splitText)
                {
                    if ((buildstring + " " + text).Length > 60)
                    {
                        wrappedText.Add(buildstring);
                        buildstring = text;
                    }
                    else
                    {
                        buildstring = buildstring + " " + text;
                    }
                }
                foreach (var outputText in wrappedText)
                {
                    Console.WriteLine(outputText);
                }
            }
            Console.WriteLine("\n\nPress any key to contine.");
            Console.ReadLine();
        }
    }
}

Finally our program is producing some pretty wrapped text.

 Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Phasellus pretium placerat dictum. Curabitur tristique enim
ut purus iaculis, nec tempor risus aliquam. Integer quis

...

in sagittis tellus. Etiam facilisis quam nibh, non elementum
velit fermentum in. Suspendisse bibendum nunc aliquet lorem


Press any key to contine.

 

Creating the Extension Method

Why We Need an Extension Method.

This code works, but its is ugly.  The logic is also harder to understand than it should be.  Frankly, we need to create an extension class to better organize our code.  In fact, organization is the whole point of extension methods.  Extension methods provide a technique to more closely associate functionality with existing types.  We will move our newly defined functionality out of the Main method and attach it to the string type.

Add a new static class

At this point, you will create a new static class to hold the extension method’s code.  In visual studio, create a new file.  Name the file “StringExtensions.cs.”

New StringExtension.cs Class source file

New StringExtension.cs Class source file in VS Code Project Explorer

Make sure the class is public and static.  Also make sure the the class’s name space matches the program class’s name space.  In my example name space needed to be “Examples.ExtensionsMethod.” It is a good practice for the source code file name and the contained class to share a name.

using System;

namespace Examples.ExtensionMethod
{
    public static class StringExtensions
    {
      // TODO: Extension Method 
    }
}
Create an Extension Method

Extension methods have a couple requirements that have to be met.  First extension methods must be public and static.  Second, the type being extended must be passed into the method as the first argument.  This argument will use the special “this” keyword.  Name the new method “WordWrap”

using System;

namespace Examples.ExtensionMethod
{
    public static class StringExtensions
    {
       public static void WordWrap(this string str)
        { }
    }
}

While the above code is an extension method, it is kind of useless.  In addition to the argument for class we are extending, we are going to also have the max text string length passed into the method as an argument.  Further, we are going to have the method return an IEnumerable<string>.

using System;

namespace Examples.ExtensionMethod
{
    public static class StringExtensions
    {
       public static IEnumerable WordWrap(this string str, int? lineLength)
        {
           return new List();
        }
    }
}
Moving the logic

Now we are ready to move in the logic from the Program class.  For the most part, you will be only copying and pasting the word wrap code from the Main method.  Some of the minor changes will be incorporating the lineLength argument.  To this end, I added a check against lineLength.  I wanted to make sure that information passed in was valid.  If a no linelength is passed in  or it is invalid, the method will load the unaltered original string into the wrappedText object.  Oh yes, I also added a

using System;
using System.Collections.Generic;

namespace Examples.ExtensionMethod
{
    public static class StringExtensions
    {
        public static IEnumerable WordWrap(this string str, int? lineLength)
        {

            List<string> wrappedText<string> = new List();

            if(lineLength == null || lineLength <= 0)
            {
                wrappedText.Add(str);
                return wrappedText;
            }

            string[] splitText = str.Split(' ');

            var buildstring = String.Empty;
            foreach (var text in splitText)
            {
                if ((buildstring + " " + text).Length > lineLength)
                {
                    wrappedText.Add(buildstring);
                    buildstring = text;
                }
                else
                {
                    buildstring = buildstring + " " + text;
                }
            }

            return wrappedText;
        }
    }
}
refactor the Program Class

Finally, we can now remove the word-wrap logic form the Main method.  For readability, I replaced “string line” with “var lines“.  Then, I modified the foreach loop, that was outputting wrappedText, to instead output from the lines collection.  In addition, I added another writeLine before the wrapped text output.  The new write-in just output a couple “\n” new line characters.  The additional lines helped output readability.

using System;
using System.Collections.Generic;
using System.IO;

namespace Examples.ExtensionMethod
{
    class Program
    {
        static void Main(string[] args)
        {
            FileStream fileStream = new FileStream("sampleText.txt", FileMode.Open);
            using (StreamReader reader = new StreamReader(fileStream))
            {
                var lines = reader.ReadLine().WordWrap(60);
                Console.WriteLine("\n\n");
                foreach (var line in lines)
                {
                    Console.WriteLine(line);
                }

            }
            Console.WriteLine("\n\nPress any key to contine.");
            Console.ReadLine();
        }
    }
}

Compile and run the program.  You should once again get some nicely formatted output.

Wrap Up

I’ll be the first to admit, that this example is ridiculous, but that was not the point.  This was a demonstration of how to use an extension method to help organize code.   Initially, we had written new functionality.  However, we needed to associate the word-wrap class with the string type.  Hence we used an extension method to attach the new word wrap functionality  to the string type.

 

Thanks for reading!

Mathew Casper

 

I’ve attached the code for today below.

Examples.ExtensionMethod.zip

Categories: Language Structures

1 Comment

Seth · September 22, 2017 at 8:22 pm

60 characters per line of text…that sounds familiar.

Leave a Reply