Mọi kiểu trong .NET đều có một tên đầy đủ gồm namespace và tên kiểu: System.Console, System.Collections.Generic.List<T>, System.Text.StringBuilder. Namespace nhóm các kiểu liên quan và giữ cho tên không bị trùng, nhờ vậy lớp Order hay Timer của bạn có thể tồn tại song song với các lớp cùng tên trong thư viện. Chỉ thị using (using directive) ở đầu tệp import một namespace để bạn dùng được tên ngắn.
Đầu ra:
Cart: tea, honey
1
Chỉ thị using chỉ ảnh hưởng đến tên lúc biên dịch. Nó không nạp thư viện hay thêm code vào chương trình; thư viện nào dùng được là do các tham chiếu và package NuGet của dự án quyết định. Nếu trình biên dịch báo một kiểu hoặc namespace "could not be found (are you missing a using directive or an assembly reference?)", tức lỗi CS0246, thì hoặc là thiếu dòng using, hoặc là package chưa được tham chiếu.
Khai báo namespace của riêng bạn
Đặt các kiểu bên trong một khối namespace. Namespace có thể lồng nhau, viết bằng dấu chấm, và cùng một namespace có thể trải ra nhiều tệp.
Đầu ra:
120.00 via DHL
Shop.Billing.Invoice
namespace Shop.Billing { } là cách viết tắt của namespace Shop { namespace Billing { } }. Code bên trong Shop có thể gọi Billing.Invoice mà không cần tiền tố Shop., vì tên được tìm trong các namespace bao quanh trước.
Quy ước: bắt đầu bằng tên công ty hoặc sản phẩm (Contoso.Payments), sau đó là tính năng hoặc tầng, và khớp với cấu trúc thư mục (Contoso.Payments/Refunds/RefundService.cs chứa Contoso.Payments.Refunds). Đừng bao giờ đặt tên lớp trùng với namespace của nó (Shop.Shop), vì điều đó buộc bạn phải ghi tên đầy đủ một cách vụng về ở khắp nơi.
Alias
using Name = Namespace.Type; đặt cho một kiểu (hoặc một namespace) một tên cục bộ. Có hai tình huống cần đến nó: rút ngắn một kiểu generic dài, và giải quyết xung đột tên.
Đầu ra:
latte: 3.60
order 17
Alias chỉ có hiệu lực trong tệp khai báo nó (trừ khi là global, xem bên dưới). Từ C# 12 trở đi, alias có thể đặt tên cho mọi kiểu, kể cả tuple và mảng: using Point = (int X, int Y);.
Tham chiếu mơ hồ (CS0104)
Khi hai namespace được import cùng chứa một kiểu trùng tên, dùng tên ngắn sẽ bị lỗi. Trường hợp kinh điển là Timer, có trong System.Threading, System.Timers và (ở ứng dụng desktop) System.Windows.Forms:
using System.Threading;
using System.Timers;
var t = new Timer(1000);
// error CS0104: 'Timer' is an ambiguous reference between
// 'System.Timers.Timer' and 'System.Threading.Timer'
Ba cách sửa, từ cục bộ nhất đến ít cục bộ nhất: viết tên đầy đủ (new System.Timers.Timer(1000)), thêm một alias chỉ rõ bạn muốn dùng cái nào, hoặc xóa chỉ thị bạn không cần.
Đầu ra:
250
System.Timers.Timer
System.Threading.Timer
Nếu namespace của bạn định nghĩa một kiểu tên System hoặc Console, tiền tố global:: buộc việc tìm kiếm bắt đầu từ gốc: global::System.Console.WriteLine("hi");. Code được sinh tự động dùng nó ở khắp nơi vì lý do này.
using static
using static import các thành viên static của một kiểu, để gọi chúng mà không cần tên kiểu. Nó hợp với code gọi đi gọi lại cùng một lớp, như Math:
Đầu ra:
Area: 28.27
Hypotenuse: 5
42
using static cũng dùng được với enum (using static System.DayOfWeek; cho phép bạn viết Monday) và với các lớp static của bạn. Hãy dùng nó ở nơi tên ngắn vẫn không gây nhầm lẫn; một WriteLine đứng một mình trong tệp lớn có thể khiến người đọc phân vân không biết đó là writer nào.
global using và file-scoped namespace (C# 10)
Hai tính năng của C# 10 giúp cắt bớt phần khai báo lặp lại ở đầu tệp. global using áp dụng cho mọi tệp trong dự án, và thường được đặt trong một tệp riêng như GlobalUsings.cs:
// GlobalUsings.cs, C# 10 and later
global using System;
global using System.Collections.Generic;
global using System.Linq;
global using Money = System.Decimal;
Các dự án SDK từ .NET 6 trở đi có thể tự sinh chúng cho bạn. Với <ImplicitUsings>enable</ImplicitUsings> trong .csproj (mặc định trong các template mới), một dự án console nhận được System, System.Collections.Generic, System.IO, System.Linq, System.Net.Http, System.Threading và System.Threading.Tasks; dự án web nhận thêm các namespace của ASP.NET Core. Đó là lý do các tệp Program.cs hiện đại bắt đầu ngay bằng code.
File-scoped namespace khai báo namespace cho cả tệp bằng một dấu chấm phẩy thay vì một khối, giảm được một cấp thụt lề:
// C# 10 and later
namespace Shop.Billing;
public class Invoice
{
public decimal Amount { get; set; }
}
Mỗi tệp chỉ có một file-scoped namespace, và không thể trộn nó với namespace dạng khối trong cùng tệp. Các dự án cũ, script Unity và code nhắm tới .NET Framework dùng dạng khối như ở trên.
Vị trí của chỉ thị using, và câu lệnh using
Chỉ thị using phải đứng trước mọi khai báo namespace hoặc kiểu trong tệp (global using đứng trước tất cả). Chúng cũng có thể đặt bên trong một khối namespace, khi đó chỉ có hiệu lực ở đó; các style guide có ý kiến khác nhau, và phần lớn code .NET giữ chúng ở đầu tệp.
Từ khóa using còn có một nhiệm vụ thứ hai, không liên quan, bên trong phương thức: câu lệnh using using (var file = File.OpenRead(path)) { ... } gọi Dispose trên đối tượng khi khối lệnh kết thúc, giúp đóng tệp và kết nối. Hai thứ chỉ dùng chung từ khóa, ngoài ra không có gì chung. Xem trang câu lệnh using.
Câu hỏi thường gặp
using trong C# dùng để làm gì?
Ở đầu tệp, using System.Text; là một chỉ thị import một namespace, nhờ đó bạn có thể viết StringBuilder thay cho System.Text.StringBuilder. Nó không thêm code và không nạp gì cả; nó chỉ rút ngắn tên. Bên trong một phương thức, using (var f = ...) là một tính năng khác, câu lệnh using, dùng để dispose một đối tượng khi kết thúc khối lệnh.
Namespace trong C# là gì?
Namespace là một nhóm kiểu có tên, giúp tránh trùng tên và tổ chức code, chẳng hạn System.Collections.Generic hoặc MyShop.Billing. Hai lớp có thể trùng tên nếu nằm trong các namespace khác nhau. Theo quy ước, namespace đi theo cấu trúc thư mục và bắt đầu bằng tên công ty hoặc tên sản phẩm.
using static trong C# là gì?
using static System.Math; import các thành viên static của một kiểu, nên bạn có thể gọi Sqrt(16) và đọc PI mà không cần tiền tố Math.. Nó dùng được với mọi lớp, kể cả lớp của bạn và enum. Hãy dùng nó ở những nơi tên ngắn vẫn rõ nghĩa, như code tính toán nhiều.
Làm sao sửa lỗi "is an ambiguous reference" trong C#?
Lỗi CS0104 nghĩa là hai namespace được import đều chứa một kiểu cùng tên, ví dụ Timer trong System.Threading và System.Timers. Hãy viết tên đầy đủ (System.Timers.Timer), xóa một trong hai chỉ thị using, hoặc thêm alias: using Timer = System.Timers.Timer;.
global using trong C# là gì?
global using System.Text; (C# 10) import một namespace cho mọi tệp trong dự án, không chỉ tệp chứa nó. Các dự án SDK từ .NET 6 trở đi tự sinh một bộ global using khi đặt <ImplicitUsings>enable</ImplicitUsings>, đó là lý do các tệp Program.cs mới không có dòng using nào.