Professor Mustard Programming
 

Programming 101 - Unit 04 - OOP

04f) Namespaces
 
This is probably a good time to address the issue of separate files. If you're working on a big project, you probably don't want your entire program to exist in one monster-sized source-code file. How, though, do you go about breaking your program up into different files?

The normal (and recommended) approach is to have one file per class. Each file bears the name of the class it defines. For example, the file that defines the Pizza class would be called "Pizza.cs".

Remember that you need to put the "using [nameofnamespace]" statements at the top of every file that will need them. If both files need System.Collections, then make sure they both have a using statement for it. If only one files needs it, then only put the using statement for System.Collections in that one file.

By the way, have you noticed that I've never had Console.WriteLine() or console.ReadLine() in any of my classes? They've always been limited to the main program, and there's a good reason for that. Once again, it's all about encapsulating a class's responsibilities. The responsibility of the Pizza class is to represent a pizza, and maybe do some pizza-related calculations. It's the responsibility of the Main() program to actually use that pizza, and that includes displaying it on the console.

The main issue here is code reuse. All our little Class1 application will ever be good for is writing some cheesy little output strings to the console, so that's where we want to put all of our console code. The Pizza class, on the other hand, has the potential to be used anywhere... in a Windows Forms project, in a web-based ASP project, or even in a windows-based service, where there's no visual elements at all. But as soon as we put console statements into that Pizza class, we've just made it dependant on the console environment: in any other situation, it won't work the same.

An important realization you eventually make as a programmer is the distinction between business logic and presentation. Business logic is universal, regardless of the user interface, and it can be done just about anywhere in the program (hopefully in a place that makes sense)! Furthermore, it occurs inside the processor, where the user never sees it. Presentation, on the other hand, is a very specific part of your code. All it does is provide the user with an interface they can use to get results from (and possibly interact with) your program. Of course, the presentation part is also arguably the most important, since it's the main reason the program exists - if a program calculates perfectly, but can't display its results to the user correctly, then it's useless. The point is that you should make an effort to separate presentation from business logic whenever possible, since it will make it easier to reuse both in future projects. But I digress.

Okay, as long as we're talking about separate files, we might as well mention namespaces, so that you finally know what each and every word in these code samples is actually doing. Namespaces were invented for a simple reason: naming conflicts. What's a program supposed to do if it's using two code libraries, and each one contains a class called "Cat"? You need some way to tell C# which one you're actually going to use. As long as each library uses a different namespace, you can do that.

Take a look at this lesson's code sample. The first file contains Class1, and it's declared in the "F_SeparateFiles" namespace (like anything else, you can call namespaces whatever you want... in Visual Studio, the namespace name will default to the name of your project). The second file contains Pizza, but it's declared in a different namespace, "MyNewNamespace". So, in order to use the Pizza class from Main(), we have to write a "using MyNewNamespace" statement in Class1.cs. It's even easier when both files use the same namespace, because you don't need any extra "using" statements at all! In the vast majority of cases, you should probably use the same namespace across your entire project for simplicity, unless there's a really good reason for splitting everything up.

By the way, if you want to hide one of your classes from someone else who might use your namespace, you can put the "internal" keyword in from of it, as in "internal class pizza", so that only classes in the same namespace will have access to it.



<<< "Class1.cs" >>>
using System;
using MyNewNamespace;

namespace F_SeparateFiles
{
  class Class1
  {
    static readonly string ln = Environment.NewLine;

    [STAThread]
    static void Main(string[] args)
    {
      // Create a "default" pizza, and print its information
      Pizza pizza1 = new Pizza();
      Console.WriteLine("PIZZA1 after construction:");
      Console.WriteLine(" Topping = " + pizza1.Topping);
      Console.WriteLine(" Diameter = " + pizza1.Diameter);
      Console.WriteLine(" Radius = " + pizza1.GetRadius());
      Console.WriteLine(" CookName = " + pizza1.CookName);

      // Change the pizza's information
      pizza1.Topping = "Pineapple";
      pizza1.Diameter = 9.0;

      // Re-print its information
      Console.WriteLine(ln + "PIZZA1 after changing its information:");
      Console.WriteLine(" Topping = " + pizza1.Topping);
      Console.WriteLine(" Diameter = " + pizza1.Diameter);
      Console.WriteLine(" Radius = " + pizza1.GetRadius());
      Console.WriteLine(" CookName = " + pizza1.CookName);

      // Create a "custom" pizza, and print its information
      Pizza pizza2 = new Pizza("Pepperoni", 6.0, "Tony");
      Console.WriteLine(ln + "PIZZA2 after construction:");
      Console.WriteLine(" Topping = " + pizza2.Topping);
      Console.WriteLine(" Diameter = " + pizza2.Diameter);
      Console.WriteLine(" Radius = " + pizza2.GetRadius());
      Console.WriteLine(" CookName = " + pizza2.CookName);

      PromptForExit();
    }

    static void PromptForExit()
    {
      Console.Write(ln + "Program complete! Hit enter to exit...");
      Console.ReadLine();
    }
  }
}


<<< "Pizza.cs" >>>
using System;

namespace MyNewNamespace
{
  class Pizza
  {
    private string _topping;
    private double _diameter;
    private string _cookName;
    public string Topping { get{ return _topping; } set{ _topping = value; } }
    public double Diameter { get{ return _diameter; } set{ if( value >= 0 ) _diameter = value; } }
    public string CookName { get{ return "Chef " + _cookName; } }

    public Pizza()
    {
      _topping = "";
      _diameter = 0.0;
      _cookName = "Anonymous";
    }

    public Pizza(string topping, double diameter, string cookName)
    {
      _topping = topping;
      _diameter = diameter;
      _cookName = cookName;
    }

    public double GetRadius()
    {
      return _diameter / 2.0;
    }
  }  
}