Theme index -- Keyboard shortcut: 'u'  Previous theme in this lecture -- Keyboard shortcut: 'p'  Next slide in this lecture -- Keyboard shortcut: 'n'Reference types, Value types, and Patterns

A complete PDF version of the text book is now available. The PDF version is an almost complete subset of the HTML version (where only a few, long program listings have been removed). See here.

15.  Organization of C# Programs

This chapter is of a different nature than the previous chapters.

At this point you are supposed to be able to program simple classes, like the Die class in Program 10.1, the Point class in Program 11.2, and the BankAccount class in Program 11.5. Eventually, it will be necessary to care about how classes are organized in relation to each other. We chose to cover C# program organization now. In case you are not motivated for these issues, you can skip the chapter at this point in time. But you are advised to come back to it before you start writing large C# programs.

If you want to read more about the organization of C# programs, you are recommended to study chapter 16 of C# Language Specification [ECMA-334].

We show a lot of examples in this chapter. In the web edition, all examples are present. In the paper edition, only the most fundamental examples appear. Therefore, if you want to understand all the details of this chapter, read the web edition.

15.1 Program Organization15.3 Namespaces and Visibility
15.2 Examples of Program Organization15.4 Namespaces and Assemblies
 

15.1.  Program Organization
Contents   Up Previous Next   Slide Annotated slide Aggregated slides    Subject index Program index Exercise index 

The structure and organization of a C# program is radically different from the structure and organization of both C programs and Java programs. Below we emphasize some important observations about the organization of C# programs.

  • C# programs are organized in namespaces

    • Namespace can contain types and - recursively - other namespaces

  • Namespaces (and classes) in relation to files:

    • One of more namespaces in a single file

    • A single namespace in several files

    • A single class in several files - partial classes

  • The mutual order of declarations is not significant in C#.

    • No declaration before use.

  • When compiled, C# programs are organized in assemblies

    • .exe and .dll files

As noticed above, a single namespace can be spread out on several source files. In Section 11.12 we have also seen that a single class - called a partial class - can be defined in two or more source files.

 

15.2.  Examples of Program Organization
Contents   Up Previous Next   Slide Annotated slide Aggregated slides    Subject index Program index Exercise index 

In the majority of the small programs, which we present in this material, namespaces do not appear explicitly. Most of the programs we have shown until now in this material follow the pattern of Program 15.1.

1
2
3
4
5
6
7
8
9
10
11
12
13
// The most simple organization
// A class located directly in the global namespace
// In source file ex.cs

using System;

public class C { 

  public static void Main(){
    Console.WriteLine("The start of the program");
  }

}
Program 15.1    A single class in the anonymous default namespace.

In Program 15.1 the class C is a member of the (implicitly stated) global name space. The compilation of the program in Program 15.1 can be done as shown in Listing 15.2 (only on web).

1
2
3
4
5
In Windows SDK 
csc ex.cs

In Mono
gmcs ex.cs
Listing 15.2    Compilation of a single class in the anonymous default namespace.

Below, in Program 15.3 the namespaces N1 and N2 are members of the global name space. N2 contains a nested namespace called N3.

You should use namespaces to group types that somehow belong together, either conceptually or according the architecture of the software you are creating. Namespaces are also useful if you have identically named types (such as two classes with the same name) that should coexist. In that case, place the conflicting types in different namespaces, and be sure to use the involved namespaces with qualified access - "namespace dotting". Use of several namespaces, such as N1, N2, and N3 in Program 15.3 is, in general, relevant only in large programs with many types.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Several namespaces, including nested namespaces.
// In source file ex.cs

namespace N1 {
  public class C1{};
}


namespace N2 {
  internal class C2{};
  public class C3{};

  namespace N3 {
     public class C4{
       C2 v;
     }
  }
}
Program 15.3    Two namespaces and a nested namespace with classes.

In Program 15.4 we show how to use the classes C1, C2, C3, and C4 from Program 15.3. The using directives import the types of a namespace. Importing a namespace N implies that types T in N can be used without qualification. Thus, we can write T instead of N.T. The three using directives in line 15-17 of Program 15.4 open up the namespaces N1, N2 and N2.N3. If the namespaces in Program 15.3 and the client class shown in Program 15.4 are compiled to two different assemblies (dll files) then C2 cannot be used in the Client class. The reason is that C2 is internal in its assembly.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// A client program
// In source file client.cs


/*
  Namespace N1
    public class C1
  Namespace N2
    internal class C2 
    public class C3 
    Namespace N3
      public class C4
*/

using N1;
using N2;
using N2.N3;

public class Client{
  C1 v = new C1(); 

  // The type or namespace name 'C2' could not be found.
  // C2 w = new C2();   
  C3 x = new C3(); 
  C4 y = new C4(); 
}
Program 15.4    A client of classes in different namespaces.

If you avoid the using directives, you are punished with the need to use a lot of "namespace dotting". If you wish to see the effect of this, please consult Program 15.5 (only on web)

The compilation of Program 15.3 together with Program 15.5 and Program 15.4 (only on web) is shown in Listing 15.6 (only on web).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// An equivalent client program. No using clauses.
// In source file client-equiv.cs


/*
  Namespace N1
    public class C1
  Namespace N2
    internal class C2 
    public class C3 
    Namespace N3
      public class C4
*/


// No using clauses - instead fully qualified class names:

public class Client{
  N1.C1 v = new N1.C1(); 

  // The type or namespace name 'C2' could not be found.
  // N2.C2 w = new N2.C2();   
  N2.C3 x = new N2.C3(); 
  N2.N3.C4 y = new N2.N3.C4(); 
}
Program 15.5    An equivalent client of classes in different namespaces - no using clauses.

1
2
3
4
5
6
7
8
9
In Windows SDK
csc /target:library ex.cs
csc /target:library /reference:ex.dll client.cs
csc /target:library /reference:ex.dll client-equiv.cs

In MONO
gmcs /target:library ex.cs
gmcs /target:library /reference:ex.dll client.cs
gmcs /target:library /reference:ex.dll client-equiv.cs
Listing 15.6    Compilation of the namespaces and client.

Nested namespaces can be given by textual nesting, as shown in Program 15.3 or in Program 15.7 (only on web). Alternatively, it can be given as shown in Program 15.8. In Program 15.8 the namespaces N2 and N3 are both member of the namespace N1. Thus, the situation in Program 15.8 is identical to the situation shown in Program 15.7 (only on web).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Again nested namespaces. N1 contains N2 and N3.
// In source file ex.cs

namespace N1 {

  namespace N2 {
   public class C1{};
   public class C2{};
  }

  namespace N3 {
      public class C3{}
  }

}
Program 15.7    Nested namespaces with classes.

1
2
3
4
5
6
7
8
9
10
11
12
// Equivalent to the previous program 
// No physical namespace nesting 
// In source file ex-equiv.cs

namespace N1.N2 {
  public class C1{};
  public class C2{};
}

namespace N1.N3 {
  public class C3{}
}
Program 15.8    Equivalent program with nested namespaces - no physical nesting.

The classes C1, C2, and C3 of either Program 15.8 or Program 15.7 (only on web) can be used in a Client class, as shown in Program 15.9 (only on web). The compilation can be done as shown in Listing 15.10 (only on web).

1
2
3
4
5
6
7
8
9
10
// In source file client.cs

using N1.N2;
using N1.N3;

public class Client{
  C1 x = new C1(); 
  C2 y = new C2(); 
  C3 z = new C3(); 
}
Program 15.9    A client of classes in nested namespaces.

1
2
3
4
5
6
In Windows SDK
csc /target:library ex.cs
csc /target:library /reference:ex.dll client.cs

csc /t:library ex-equiv.cs
csc /t:library /r:ex-equiv.dll /out:client-equiv.dll client.cs
Listing 15.10    Compilation of the namespaces and client.

A namespace, such as Intro in Program 15.11 is open ended in the sense that stuff can be added to Intro from another source file. Both Program 15.11 and Program 15.12 contribute to the Intro namespace. Thus, when the two source files are taken together, Intro contains the types A, B, and C. The use of the namespace Intro is shown in Client class in Program 15.13 (only on web). In Listing 15.14 (only on web) we show how to compile the two source files f1.cs and f2.cs behind the namespace Intro together.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// f1.cs: First part of the namespace Intro

using System;

namespace Intro{

  internal class A {

    public void MethA (){
      Console.WriteLine("This is MethA in class Intro.A");
    }
  }

  public class B {

    private A var = new A();

    public void MethB (){
      Console.WriteLine("This is MethB in class Intro.B");
      Console.WriteLine("{0}", var);
    }
  }

}
Program 15.11    Part one of namespace Intro with the classes A and B.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// f2.cs: Second part of the namespace Intro

using System;

namespace Intro{

  public class C {
    private A var1 = new A();   
    private B var = new B();

    public void MethC (){
      Console.WriteLine("This is MethC in class Intro.C");
      Console.WriteLine("{0}", var);
      Console.WriteLine("{0}", var1);
    }
  }
}
Program 15.12    Part two of namespace Intro with the class C.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// client.cs: A client of the classes in namespace Intro


/* 
    namespace Intro
      internal class A
      public class B
      public class C
*/


using System;
using Intro;

class Client {

  public static void Main(){
//  A a = new A();   // Compiler error: Class A is internal in Intro
    B b = new B();
    C c = new C();

    Console.WriteLine("{0} {1}", b, c);
  }
}
Program 15.13    A client class that uses the classes in namespace Intro.

The problem reported in line 18 of Program 15.13 relies on the compilation of the program to two different assemblies, as shown in Listing 15.14. If both the Intro namespace and the Client class are compiled to a single assembly there will be no error in line 18.

1
2
3
4
5
6
7
8
9
10
11
12
In Windows SDK
csc /target:library /out:assembly.dll f1.cs f2.cs
csc /reference:assembly.dll client.cs

client.exe


In MONO:
gmcs /target:library /out:assembly.dll f1.cs f2.cs
gmcs /reference:assembly.dll client.cs

mono client.exe
Listing 15.14    Possible compilation of namespace Intro and class Client.

The compilations shown in Listing 15.14 illustrate how to compile the files f1.cs and f2.cs together. In general, it is possible to compile a number of C# source files together as though these source files were contained in a single large source file. This way of compilation is often an easy way to compile a number of C# source files that depend on each other in circular ways. Alternatively, each file must be compiled in isolation and in a particular order, with use of the reference compiler option.

Notice also, from Listing 15.14, that you can control the name of the assembly via use of the out compiler option.

 

15.3.  Namespaces and Visibility
Contents   Up Previous Next   Slide Annotated slide Aggregated slides    Subject index Program index Exercise index 

In this section we summarize the visibility rules of types and namespaces, both of which can occur in (other) namespaces.

  • Types declared in a namespace

    • Can either have public or internal access

    • The default visibility is internal

    • Internal visibility is relative to an assembly - not a namespace

  • Namespaces in namespaces

    • There is no visibility attached to namespaces

    • A namespace is implicitly public within its containing namespace

You should pay attention to the default visibility of types in namespaces. If you do not give a visibility modifier of a type T (a class, for instance) in a namespace N, T is internal in N. This may lead to surprises if you in reality forgot to state that T should have been public. We have already discussed this in Section 11.16.

 

15.4.  Namespaces and Assemblies
Contents   Up Previous Next   Slide Annotated slide Aggregated slides    Subject index Program index Exercise index 

  • Namespaces

    • The top-level construct in a compilation unit

    • May contain types (such as classes) and nested namespaces

    • Identically named members of different namespaces can co-exist

    • There is no coupling between classes/namespaces and source files/directories

  • Assemblies

    • A packaging construct produced by the compiler

      • Not a syntactic construct in C#

    • A collection of compiled types - together with resources on which the types depend

    • Versioning and security settings apply to assemblies

The file/directory organization, the namespace/class organization and the assembly organization are relatively independent of each other

 

15.5.  References
[Ecma-334]"The C# Language Specification", June 2005. ECMA-334.

Generated: Monday February 7, 2011, 12:14:42
Theme index -- Keyboard shortcut: 'u'  Previous theme in this lecture -- Keyboard shortcut: 'p'  Next slide in this lecture -- Keyboard shortcut: 'n'