Namespaces in C#

Namespaces organize related types and help prevent naming conflicts. A namespace can contain classes, structs, interfaces, enums, delegates, and other namespaces.

The traditional namespace declaration

Before C# 10, namespaces were commonly declared with braces. This is called a block-scoped namespace:

namespace MyApp.Models
{
    public class Customer
    {
        public string Name { get; set; } = string.Empty;
    }
}

All types in the namespace must be placed inside the braces. If a file contains several namespaces, each one gets its own block.

The new file-scoped declaration

C# 10 introduced file-scoped namespaces. The namespace is followed by a semicolon, and everything else in the file belongs to that namespace:

namespace MyApp.Models;

public class Customer
{
    public string Name { get; set; } = string.Empty;
}

This syntax removes one level of indentation and makes files with a single namespace easier to scan. A file-scoped namespace must appear before the type declarations in the file, and a file cannot contain both a file-scoped namespace and a block-scoped namespace.

Nested namespaces

With the traditional syntax, nested namespaces are written as nested blocks:

namespace MyApp
{
    namespace Services
    {
        public class EmailService
        {
        }
    }
}

The same namespace can be written more clearly using a dotted name:

namespace MyApp.Services;

public class EmailService
{
}

Using types from another namespace

The using directive lets a file refer to types without writing their fully qualified names:

using MyApp.Models;

namespace MyApp.Services;

public class CustomerService
{
    public Customer CreateCustomer(string name) => new() { Name = name };
}

Without a using directive, the type can be referenced by its full namespace name:

namespace MyApp.Services;

public class CustomerService
{
    public MyApp.Models.Customer CreateCustomer(string name) =>
        new() { Name = name };
}