It's just one line of code right?

Let's assume for the sake of argument that you actually need to write an application that just writes "Hello World!" to the console. So, let's follow the most common approach first. Just create a new console application in visual studio and put the following code in your main method in Program.cs:

Console.Write("Hello World!");

Just hit F5 and you are done, right? Of course not! But what is wrong? Where do we start?

Goodbye ConsoleApplication1

If you get paid to write code, and you have ConsoleApplication1, ClassLibrary1, Form1, or Class1 in your application, your coworkers will laugh at you (I know I did). This is a horribly annoying naming convention that is completely useless. I'll go into this more in Projects and Namespaces but for now let's focus on the fact that this is truly the name of your program. If you created your ConsoleApplication1 and compiled it, you might have noticed that it created ConsoleApplication1.exe. This is what shows up in your task manager so if your program runs amok and someone goes to shut it down, that is just one more person who will laugh at you when they see ConsoleApplication1.exe. I do like to stay consistent between my project names and assembly names, so let's call the project "HelloRealWorldConsole".

But what about the namespace?

You might be asking, "What is wrong with the namespace? That looks like every other namespace I see on CodePlex." Does it look like anything you see from Microsoft or any major provider of .Net tools (free or otherwise)? All the .Net namespaces start with System and all the various Microsoft tools that aren't part of the framework start with Microsoft. If you have a company, I would start all of your namespaces with your company name. Since we don't have a company, we are going to use the project name (HelloRealWorld). But it is always going to be HelloRealWorld.Something. To me the logical choice following the law of least astonishment is HelloRealWorld.Console. So let's go into the properties of the project and change the Default namespace value to HelloRealWorld.Console. Since Visual Studio was nice enough to assume we wanted our namespace to match our assembly name, let's go into Program.cs and put a dot between "HelloRealWorld" and "Console":

namespace HelloRealWorld.Console

So what's next?

A simple place to start is by letting Visual Studio tell you what it has done wrong. If you have a team edition of Visual Studio you can run code analysis to see what comes up. Here is what you will see after writing only one line of code (or even if you don't write any):
  • CA2210 : Microsoft.Design : Sign 'ConsoleApplication1.exe' with a strong name key.
  • CA1801 : Microsoft.Usage : Parameter 'args' of 'Program.Main(string[])' is never used. Remove the parameter or use it in the method body.

Let's look at the second problem first. Just because the Visual Studio templates give you some code doesn't mean it has to be that way. We aren't going to do anything with command-line arguments so let's get rid of the parameter in the main method:

static void Main()

Do I really need to sign my assemblies?

The short answer is no. The slightly less short answer is that it makes your assemblies more secure so it is a good idea in general, but can cause some difficulties so research some more yourself (check out this blog entry for example) and do what you think is best. We are going to sign our assemblies because it is generally a good idea.

Documentation Schmockumentation!

Self-documentation is a great feature of C#. Unfortunately it is only partially enabled by default in Visual Studio. Let's go into our project properties again and go to the "Build" tab. Then check the box labeled "XML documentation file" (you can leave the file name as the default). Not only will this generate an XML file with your documentation when you compile, but you will now also get compiler warnings when there are problems with the documentation.

To serve and protect

Next, let's run StyleCop to see what it has to say about our one-line program:
  • SA1633: The file has no header, the header Xml is invalid, or the header is not located at the top of the file.
  • SA1200: All using directives must be placed inside of the namespace.
  • SA1600: The class must have a documentation header.
  • SA1600: The method must have a documentation header.
  • SA1400: The class must have an access modifier.
  • SA1400: The method must have an access modifier.

SA1633 adn SA1200 are a good idea, but I am going to ignore those for now and let's move on to, "SA1400: The class must have an access modifier." Access modifiers in .Net are as follows:
  • Private
  • Protected
  • Internal
  • Public

Note: A good way to learn about access modifiers is to let Visual Studio teach you. I would look into learning about Alt-Shift-F10 - the most powerfull key combination in Visual Studio.

Private is the most restrictive modifier. Private members can only be accessed by the class in which they are contained. We don't ever want to call Main except when the program starts so let's make it private:

private static void Main()

Next we have to do something with the class. You can't make it private because then nothing would be able to access it (the compiler won't let you do that). Making it protected isn't necessary because classes are inheritable even if they are internal or public. That means your only two options are internal and public. Since the purpose of this class is to launch this application, we don't want any other assemblies accessing it so let's make it internal:

internal class Program

Now let's add our documentation headers. Type three forward slashes on the line before the class and method declarations and fill in the summaries. Just to clean up, let's also get rid of the namespaces we aren't using. Here is what we get:

using System;

namespace HelloRealWorld.Console
{
    /// <summary>
    /// Container for application entry point.
    /// </summary>
    internal class Program
    {
        /// <summary>
        /// Main entry point for the application.
        /// </summary>
        private static void Main()
        {
            Console.WriteLine("Hello World!");
        }
    }
}

Do you need reusable code to write "Hello World!" on a console window?

You might not, but I am going to assume that since you are reading this at some point in your life you will write more than one program. This means you will likely need to reuse some of your code. Note that I said "reuse". Not "copy and paste". You don't need reusable code for "Hello World!" any more than you need a program to write "Hello World!" in the first place. So let's talk a little bit about what a console is and why you would use it. The fact of the matter is that the console is primarily used for development and administrative purposes. In development, you can use it for what we used to call "printf debugging" in C++. This means you can write information out to the console to show what your program has done so that when it fails you know what has completed and what hasn't. On the other hand, simply redirecting the console output to a file gives you logging for automated processes.

Hopefully you can now see why you would need to interact with the console in general, so let's walk down the path of designing our application.

Strings are Bad

Technically, that should say "String literals are bad", but I think "Strings are Bad" just resonates better. Why are string literals bad? It is VERY rare that you will ever have a string that is only used once in your application. If you set a variable equal to "Hello World!" you are likely to check that variable later to see if it is still "Hello World!" or you may want to check other variables to see if they also say "Hello World!". Strings are case-sensitive in .Net and have to match exactly so you want to be sure that you don't accidentally type "Hello world!" or "Hello World" when what you really want is "Hello World!". For this reason, you probably want to use a constant, resource, setting, or read-only variable to store your string. Another problem is that my friends in Germany might want to see "Hallo Welt!". In this case you will probably want to use a localized setting or resource (constants and read-only variables won't really do the trick).

One quick warning about constants - constants should generally never be public or protected. Constants get set at compile time, not run time. That means if you change a constant in one assembly, you have to recompile any other assemblies which reference a public or protected constant in order for the change to be picked up.

Personally, I prefer resources for most static strings. In this case, "Hello World!" is a static message that we will reuse in every example we ever do. So let's just create a resource for it, right? Not so fast my friend. Like I said, we will reuse this message. That means that this is common code we will use again and again. So let's add a new class lilbrary project to our solution and add a resource there. Since this is a library for general common code we will call this library "HelloRealWorld.Common" and then add a reference to it in HelloRealWorldConsole.

Now let's add a resource file by going to the properties of the new class library project and clicking on the "Resources" tab and then clicking the link to create the resources file. Next just add a resource named "WelcomeMessage" with a value of "Hello World!" (don't put quotes in the resource designer, just the values). For the comment, let's say, "Message displayed for demonstration."

How do I get at my new fancy resource?

You might be able to figure out that you can get at that resource in your "Class1" class via Properties.Resources.WelcomeMessage. You might also figure out that this property is internal. That means that you can't access it from the console application that is now referencing this library. So we need a way to manage this content so we can access it from outside the library. Let's rename "Class1.cs" to "ContentManager.cs". You might have also noticed that the WelcomeMessage property was static and read-only - it is always available without having to create an instance of anything and does not have a set accessor. So let's create a static read-only property in our class called "WelcomeMessage" and expose that resource value. Since we only have static members in this class, we can make the class static (there is a performance benefit to that). Don't forget to add your comments, get rid of those extra namespaces, strongly sign your assembly, and turn on the XML documentation for the project. Now your content manager should look like this:

namespace HelloRealWorld.Common
{
    /// <summary>
    /// Provides static properties for application content.
    /// </summary>
    public static class ContentManager
    {
        /// <summary>Gets the WelcomeMessage value</summary>
        public static string WelcomeMessage
        {
            get { return Properties.Resources.WelcomeMessage; }
        }
    }
}

Are we done yet?

Not quite. There is one more step. Once again, assuming that we are going to have multiple reasons to write to the console and multiple places from which we might want to write "Hello World!", we should probably put the code that does it in our common library. So let's add a ConsoleManager class to HelloRealWorld.Common and add a method to write our message out to the console. When you debug a console app in VS, it won't pause when it is complete, so let's also add a Pause method to do a Console.ReadLine(). Here is what ConsoleManager.cs should look like:

using System;

namespace HelloRealWorld.Common
{
    /// <summary>
    /// Provides methods for writing to the console.
    /// </summary>
    public static class ConsoleManager
    {
        /// <summary>
        /// Writes the welcome message to the console.
        /// </summary>
        public static void WriteWelcomeMessage()
        {
            Console.WriteLine(ContentManager.WelcomeMessage);
        }

        /// <summary>
        /// Reads a line from the console in order to pause execution.
        /// </summary>
        public static void Pause()
        {
            Console.ReadLine();
        }
    }
}


Last but not least, call these two methods in Program.cs:

using HelloRealWorld.Common;

namespace HelloRealWorld.Console
{
    /// <summary>
    /// Container for application entry point.
    /// </summary>
    internal class Program
    {
        /// <summary>
        /// Main entry point for the application.
        /// </summary>
        private static void Main()
        {
            ConsoleManager.WriteWelcomeMessage();
            ConsoleManager.Pause();
        }
    }
}


Press F5 and be amazed! That might seem like a lot of work for something that could be done in one line of code, but I hope you can see the logic behind these steps and if not it should be even more apparent in the later examples.

Last edited Jul 6, 2009 at 9:19 PM by douglampe, version 4

Comments

No comments yet.