Dela via


Namnrymder och användning av direktiv

Tips/Råd

Är du nybörjare på att utveckla programvara? Börja med självstudierna Komma igång först. De introducerar namnrymder och using direktiv när du skriver dina första program.

Har du erfarenhet av ett annat språk? Namnrymder i C# fungerar på samma sätt som paket i Java eller moduler i Python. Skumma igenom till den syntax du behöver.

Namnområdesdeklarationer och using -direktiv är relaterade språkfunktioner. En namnområdesdeklaration placerar dina typer i en ordnad struktur. Ett namnområde grupperar relaterade typer tillsammans och förhindrar namngivning av kollisioner. Ett using-direktiv tillåter programmet att använda dessa typer med endast deras enkla namn. Du behöver inte stava den fullständiga namnområdessökvägen vid varje användning.

Du har redan använt namnområden i varje C#-program som du har skrivit. Varje .NET-typ tillhör ett namnområde och varje using direktiv högst upp i en fil refererar till en. Till exempel Console och Math tillhör System namnområdet, så deras fullständigt kvalificerade namn är System.Console och System.Math. Samlingstyper som List<T> och Dictionary<TKey, TValue> tillhör System.Collections.Generic. Med ett enda using direktiv för någon av dessa namnområden kan du referera till alla dess typer med deras enkla namn. Du skriver List<T> i stället System.Collections.Generic.List<T> för överallt där du använder det.

Den här artikeln innehåller mer bakgrund om hur namnområden och using direktiv fungerar och visar exempel på mönster som du redan har stött på i .NET-bibliotek.

Ett namnområde innehåller typer. Varje .NET-typ tillhör ett namnområde. Tänk till exempel på System.Threading.Tasks.Task: typen Task tillhör System.Threading.Tasks namnområdet.

Det är bra att gruppera relaterade eller liknande typer i samma namnområde, och det är vad .NET gör med de typer som det tillhandahåller. Namnområdet System.Collections.Generic innehåller samlingsrelaterade typer och System.IO namnområdet innehåller typer relaterade till läsning och skrivning av filer, kataloger och data. Namnområdet System innehåller grundläggande typer som Math, DateTimeoch Console.

I följande exempel visas hur namnområden fungerar tillsammans med using direktiv i en typisk C#-fil:

using System.Globalization;

namespace MyApp.Services;

class Greeter
{
    public string Greet(string name)
    {
        var culture = CultureInfo.CurrentCulture;
        return $"Hello, {name}! Culture: {culture.Name}";
    }
}

I föregående exempel using innebär direktivet att du kan använda System.Globalization.CultureInfo med namnet CultureInfo utan att ange det fullständiga namnet på System.Globalization.CultureInfo. I namespace direktivet deklareras att Greeter klassen är en del av MyApp.Services namnområdet. Dess fullständigt kvalificerade namn är MyApp.Services.Greeter.

Namnområdesdeklarationer

En namnområdesdeklaration tilldelar dina typer till en namngiven grupp. Varje typ som du skriver ska tillhöra ett namnområde. Namnområdesnamnet speglar vanligtvis projektets mappstruktur. Typer i en Services/Payments mapp tillhör ofta till exempel MyApp.Services.Payments namnområdet.

Namnområden använder operatorn . för att uttrycka hierarki, till exempel System.Collections.Generic. Namnområdesnamn måste vara giltiga C# -identifierarnamn.

Fil-avgränsade namnrymder

Använd syntaxen med filomfattning när alla typer i en fil tillhör samma namnområde. Lägg till ett semikolon efter namnområdesdeklarationen och det gäller för hela filen. Du behöver inga extra klammerparenteser eller indrag:

namespace MyApp.Models;

class Customer
{
    public required string Name { get; init; }
    public string? Email { get; init; }

    public override string ToString() => $"{Name} ({Email ?? "no email"})";
}

Filomfattande namnområden minskar kapslingen och gör filer lättare att läsa. Du kan bara ha en filomfattande namnområdesdeklaration per fil.

Tips/Råd

Använd filomfattande namnområden i ny kod. De flesta .NET-mallar och kodanalysverktyg rekommenderar det här formatet.

Blockomfattande namnområden

Använd syntax med blockomfattning när du behöver deklarera mer än ett namnområde i samma fil. Det här formatet lägger till en extra indragsnivå.

Viktigt!

Det anses vara dålig praxis att deklarera mer än ett namnområde i samma fil. Det vanligaste scenariot är att använda filomfattande namnområden.

Följande kodfragment är ett exempel på ett blockomfattande namnområde:

namespace MyApp.Models
{
    class Product
    {
        public required string Name { get; init; }
        public decimal Price { get; init; }

        public override string ToString() => $"{Name}: {Price:C}";
    }
}

Använda direktiv

Utan ett using direktiv måste du referera till varje typ med dess fullständigt kvalificerade namn, den fullständiga namnområdessökvägen plus typnamnet:

static void ShowFullyQualified()
{
    // Without a using directive, use the fully qualified name:
    System.Console.WriteLine("Hello from fully qualified name!");
}

Ett using direktiv överst i en fil importerar ett namnområde så att du kan använda dess typer med deras enkla namn:

static void ShowShortName()
{
    // With 'using System;' (or implicit usings enabled), use the short name:
    Console.WriteLine("Hello from short name!");
}

Mer information finns i using direktivet.

Globala användningsdirektiv

Om du skriver samma using direktiv i varje fil kan du med globala användningsdirektiv deklarera dem en gång för hela projektet. Placera dem i valfri fil. Många team skapar en dedikerad GlobalUsings.cs fil:

global using System.Text;
global using System.Text.Json;

När du har deklarerat en global användning kan varje fil i projektet referera till typer från det namnområdet med hjälp av enkla namn utan ytterligare using direktiv.

Implicita användningar

.NET SDK genererar automatiskt global användning av direktiv för de vanligaste namnrymderna baserat på din projekttyp. Aktivera implicita användningar genom att ange <ImplicitUsings>enable</ImplicitUsings> i projektfilen. Ett konsolapplikationsprojekt importerar till exempel automatiskt System, System.Collections.Generic, System.IO, System.Linq, System.Threading och System.Threading.Tasks. Den aktuella SDK:n aktiverar ImplicitUsings när du skapar ett nytt projekt med hjälp av dotnet new.

Mer information finns i Implicit användning av direktiv.

Statiska användardirektiv

Ett static using direktiv importerar statiska medlemmar av en typ så att du kan anropa dem utan typnamnprefixet:

using static System.Math;

namespace MyApp.Utilities;

class CircleCalculator
{
    public static double CalculateArea(double radius) => PI * Pow(radius, 2);

    public static double CalculateCircumference(double radius) => 2 * PI * radius;
}

Statiska användningar fungerar bra för verktygsklasser som Math och Console som du anropar ofta.

Typ- och namnområdesalias

Ett using alias skapar ett kortnamn för en typ eller ett namnområde. Alias är användbara för långa generiska typer, för att lösa namngivningskonflikter och förbättra läsbarheten:

using CustomerList = System.Collections.Generic.List<MyApp.Models.Customer>;

namespace MyApp.Services;

class CustomerService
{
    public CustomerList GetTopCustomers()
    {
        CustomerList customers = [new() { Name = "Alice" }, new() { Name = "Bob" }];
        return customers;
    }
}

Från och med C# 12 kan du alias alla typer, inklusive tupplar och pekartyper:

using Point = (double X, double Y);

namespace MyApp.Geometry;

class Shape
{
    public static double Distance(Point a, Point b)
    {
        var dx = a.X - b.X;
        var dy = a.Y - b.Y;
        return Math.Sqrt(dx * dx + dy * dy);
    }
}

För mer avancerade scenarier där två sammansättningar definierar samma fullständigt kvalificerade typnamn använder du externt alias för att skilja mellan dem.