C# namespace
last modified October 17, 2026
In this article we cover namespaces in C#.
Namespaces are used to organize code at the highest logical level. They classify and present programming elements that are exposed to other programs and applications. Within a namespace, we can declare another namespace, a class, a record, an interface, a structure, an enumeration or a delegate.
We cannot define items such as methods, properties, fields, and events directly in a namespace. These items must be declared within types such as structures or classes. Namespaces prevent name conflicts and simplify references when using large groups of types.
Namespaces organize types in an assembly. An assembly is a reusable, versionable and self-describing building block of a .NET application. Assemblies can contain multiple namespaces, and a namespace can be spread over multiple assemblies. Namespaces can contain other namespaces. An assembly provides a fundamental unit of physical code grouping. A namespace provides a fundamental unit of logical code grouping.
Some programming languages use modules or packages for the same purpose.
C# create a namespace
The namespace keyword is used to declare a namespace in C#. The
name of the namespace must be a valid C# identifier. The parts of a nested
namespace name are separated with the . character, for instance
System.Collections.Generic. The using directive
removes the requirement to specify the name of the namespace for every type.
namespace ZetCode.Shapes
{
class Circle { }
}
A block-scoped namespace applies to the types declared between its curly braces.
namespace ZetCode.Shapes;
class Circle { }
C# 10 introduced file-scoped namespaces. When we use the namespace
keyword without curly braces, the namespace applies to the entire file. This
saves one level of indentation, and it is the usual form in modern code. A file
can contain only one file-scoped namespace, and it cannot be combined with
block-scoped namespaces.
C# file-scoped namespace
The following example uses a file-scoped namespace.
namespace ZetCode.Shapes;
record Circle(double Radius)
{
public double Area() => Math.PI * Radius * Radius;
}
class Program
{
static void Main()
{
var c = new Circle(3);
Console.WriteLine(c.GetType().FullName);
Console.WriteLine($"{c.Area():F2}");
}
}
Both the Circle record and the Program class belong to
the ZetCode.Shapes namespace.
Console.WriteLine(c.GetType().FullName);
The full name of a type includes its namespace.
$ dotnet run ZetCode.Shapes.Circle 28.27
C# namespaces and top-level statements
Top-level statements always belong to the global namespace. A file with top-level statements cannot have a file-scoped namespace, because the file-scoped namespace must precede all other members in a file. We can, however, declare block-scoped namespaces after the top-level statements.
using Shapes;
var c = new Circle(3);
Console.WriteLine(c.Area());
namespace Shapes
{
record Circle(double Radius)
{
public double Area() => Math.PI * Radius * Radius;
}
}
The Circle record is declared in the Shapes namespace.
The top-level statements import the namespace with the using
directive. In larger programs, the types are usually placed in separate files.
$ dotnet run 28.274333882308138
C# built-in namespaces
The built-in libraries are organized within namespaces.
var hostName = System.Net.Dns.GetHostName();
Console.WriteLine($"Hostname: {hostName}");
For instance, the GetHostName method belongs to the
Dns class, which is located in the System.Net
namespace. To call the method, we use its fully qualified name. A fully
qualified name is the name of a type prefixed with the name of the namespace in
which the type is defined.
using System.Net;
var hostName = Dns.GetHostName();
Console.WriteLine($"Hostname: {hostName}");
With the using directive, we import the System.Net
namespace into our program. Now we can call Dns.GetHostName
without explicitly specifying System.Net.
C# implicit and global usings
How come we can use Console without importing the
System namespace? Projects created with dotnet new
have the <ImplicitUsings>enable</ImplicitUsings>
setting in the project file. With this setting, the SDK generates a file with
global using directives for the most common namespaces. For a console
application, the file looks like this:
// <auto-generated/> global using System; global using System.Collections.Generic; global using System.IO; global using System.Linq; global using System.Net.Http; global using System.Threading; global using System.Threading.Tasks;
A global using directive applies to all files of the project. We
can declare our own global usings; they are often placed in a separate file.
global using System.Text; global using static System.Math;
We import the System.Text namespace for the whole project. The
using static directive imports the static members of a type, so we
can call them without the type name.
var sb = new StringBuilder();
sb.Append($"Square root of 2: {Sqrt(2):F4}");
sb.Append(", ");
sb.Append($"2 to the power of 10: {Pow(2, 10)}");
Console.WriteLine(sb);
We use the StringBuilder class and call Math.Sqrt
and Math.Pow without the Math prefix.
$ dotnet run Square root of 2: 1.4142, 2 to the power of 10: 1024
C# sharing namespace
In the following code, we have two files that share the same namespace.
namespace Sharing;
class Counter
{
public int Value { get; private set; }
public void Inc()
{
Value += 100;
Console.WriteLine(Value);
}
}
We have a Sharing namespace. In the namespace, we have a
Counter class.
namespace Sharing;
We declare a namespace called Sharing. The namespace applies to the
current file.
namespace Sharing;
public class Program
{
static void Main()
{
var counter = new Counter();
counter.Inc();
counter.Inc();
}
}
In the Program class, we work with the Counter class
from the previous file. We invoke its Inc method.
namespace Sharing; ...
We work in the same namespace.
var counter = new Counter(); counter.Inc(); counter.Inc();
We create an instance of the Counter class. We call its
Inc method twice. Because both types are in the same namespace, we
do not need to specify its name or import it.
$ dotnet run 100 200
C# distinct namespaces
The following code example has two distinct namespaces. We use the
using directive to import types from a different namespace.
namespace Mathematical;
public class Basic
{
public const double PI = 3.141592653589;
public static double GetPi()
{
return PI;
}
}
In the Basic class, we define a PI constant and a
GetPi method. The Basic class is defined within the
Mathematical namespace.
using Mathematical; Console.WriteLine(Basic.PI); Console.WriteLine(Basic.GetPi()); Console.WriteLine(Mathematical.Basic.PI); Console.WriteLine(Mathematical.Basic.GetPi());
In this file, we use the types from the Mathematical namespace.
using Mathematical;
We import the types from the Mathematical namespace.
Console.WriteLine(Basic.PI); Console.WriteLine(Basic.GetPi());
Now we can use those types. In our case it is the Basic class.
Console.WriteLine(Mathematical.Basic.PI); Console.WriteLine(Mathematical.Basic.GetPi());
Another way to access the types is to specify their fully qualified names.
This works even without the using directive.
$ dotnet run 3.141592653589 3.141592653589 3.141592653589 3.141592653589
C# global namespace
The global namespace is the root of all namespaces; the System
namespace and all other top-level namespaces are its members. It may happen
that we create a type or a namespace that conflicts with one from .NET. In such
cases, we can refer to the global namespace with the global::
alias.
namespace ZetCode;
class System
{
public override string ToString() => "This is System class";
}
public class Program
{
static void Main()
{
var sys = new System();
// System.Console.WriteLine(sys); error CS0117
global::System.Console.WriteLine(sys);
}
}
In our ZetCode namespace, we create a System class
that clashes with the System namespace from .NET. (Note that it is
not a good idea to create such a type.)
var sys = new System();
Here we refer to the System class from the ZetCode
namespace.
// System.Console.WriteLine(sys); error CS0117 global::System.Console.WriteLine(sys);
Inside the ZetCode namespace, the System name refers
to our class, so System.Console does not compile. With the
global:: prefix, we point to the System namespace of
the global namespace.
$ dotnet run This is System class
C# default namespace
Types that are not declared in any namespace belong to the global namespace.
struct Book
{
public override string ToString() => "Book struct in the global namespace";
}
namespace MainProgram
{
struct Book
{
public override string ToString() => "Book struct in the MainProgram namespace";
}
public class Program
{
static void Main()
{
var book1 = new Book();
var book2 = new global::Book();
Console.WriteLine(book1);
Console.WriteLine(book2);
}
}
}
We have two Book structures; one is defined in the
MainProgram namespace, the other is defined outside this namespace.
struct Book
{
public override string ToString() => "Book struct in the global namespace";
}
This Book structure is defined outside of the
MainProgram namespace. It belongs to the global namespace.
var book1 = new Book();
We refer to the structure defined inside the MainProgram
namespace. Names are looked up in the enclosing namespace first.
var book2 = new global::Book();
With the global:: prefix we point to the structure defined outside
the MainProgram namespace.
$ dotnet run Book struct in the MainProgram namespace Book struct in the global namespace
C# using alias
The using directive can also create an alias for a namespace or a
type. With nested namespaces, the fully qualified names might get long. We can
shorten them by creating aliases. Since C# 12, an alias can be created for any
type, including tuples and arrays.
using ZI = ZetCode.Items;
using Book = ZetCode.Items.Book;
using Point = (int X, int Y);
var book1 = new ZetCode.Items.Book();
var book2 = new ZI.Book();
var book3 = new ZI::Book();
var book4 = new Book();
Console.WriteLine(book1);
Console.WriteLine(book2);
Console.WriteLine(book3);
Console.WriteLine(book4);
Point p = (3, 4);
Console.WriteLine($"x: {p.X}, y: {p.Y}");
namespace ZetCode.Items
{
class Book
{
public override string ToString() => "This is a book";
}
}
In the example, we create aliases for a namespace, a class, and a tuple type.
namespace ZetCode.Items
{
class Book
{
...
}
}
The ZetCode.Items declaration is a shorthand for a
ZetCode namespace with a nested Items namespace. The
fully qualified name of the Book class is
ZetCode.Items.Book.
using ZI = ZetCode.Items; using Book = ZetCode.Items.Book; using Point = (int X, int Y);
We create a ZI alias for the namespace, a Book alias
for the class, and a Point alias for a named tuple.
var book2 = new ZI.Book(); var book3 = new ZI::Book();
The namespace alias can be used with the . or with the
:: qualifier. The :: qualifier guarantees that the
name on its left is looked up as an alias, even if a type with the same name
exists.
$ dotnet run This is a book This is a book This is a book This is a book x: 3, y: 4
Source
Declare namespaces to organize types
In this article we covered C# namespaces.
Author
List all C# tutorials.