Ngày 07 tháng 10 năm 2025
Với phiên bản .NET 10 sắp được ra mắt (tháng tới!), đã đến lúc xem xét các tính năng mới mà chúng ta có thể mong đợi trong C# 14.
Lưu ý: mục tiêu của bài viết này không phải là một danh sách đầy đủ tất cả các tính năng mới. Tôi sẽ chỉ đề cập đến những tính năng mà tôi thấy thú vị nhất. Điều này không có nghĩa là những tính năng tôi không đề cập là vô dụng, mà chỉ là chúng có các trường hợp sử dụng chuyên biệt hơn nên có lẽ sẽ không có nhiều tác động đến hầu hết các nhà phát triển.
Mục lục
Thuộc tính hỗ trợ trường (Field-backed properties)
Đôi khi còn được gọi là “thuộc tính bán tự động”, tính năng này giới thiệu từ khóa mới field trong phần thân của các bộ truy cập thuộc tính, tham chiếu đến trường hỗ trợ tự động được tạo cho thuộc tính.
Lưu ý: đây không thực sự là một tính năng mới, vì nó đã có trong C# 13 dưới dạng tính năng xem trước (bạn phải đặt phiên bản ngôn ngữ thành preview để sử dụng). Trong C# 14, nó sẽ không còn ở chế độ xem trước nữa.
Trước tiên, hãy xem xét một chút lịch sử. Trong phiên bản đầu tiên của C#, các bộ truy cập thuộc tính phải được chỉ định đầy đủ, với một trường hỗ trợ được khai báo thủ công:
private int _foo;
public int Foo
{
get { return _foo; }
set { _foo = value; }
}
Hãy thừa nhận điều này: nó khá tẻ nhạt. Trong 95% trường hợp, không có logic nào ngoài việc trả về hoặc thiết lập trường, vì vậy nó thực sự là mã không thú vị. Tôi khá chắc chắn rằng nhiều người chỉ để lộ các trường công khai để tránh phải xử lý điều đó.
Với C# 3, chúng ta có thuộc tính được triển khai tự động (đôi khi được gọi là “thuộc tính tự động”), giúp viết các thuộc tính với ít nghi thức hơn nhiều cho trường hợp phổ biến nhất (các thuộc tính chỉ bao bọc một trường mà không làm gì khác). Mã trước đó giờ có thể được viết như thế này:
public int Foo { get; set; }
Đây là một cải tiến tuyệt vời, nhưng ngay khi bạn cần làm điều gì đó khác trong các bộ truy cập (khởi tạo lười biếng thuộc tính trong lần gọi đầu tiên, thêm xác thực hoặc kích hoạt sự kiện trong bộ thiết lập, v.v.), bạn phải quay lại cách tiếp cận thủ công, bao gồm cả việc khai báo một trường hỗ trợ:
private int _foo;
public int Foo
{
get { return _foo; }
set
{
if (value < 0) throw new ArgumentOutOfRangeException();
_foo = value;
OnFooChanged();
}
}
Tính năng “thuộc tính hỗ trợ trường” mới sắp ra mắt trong C# 14 cho phép bạn có được cả hai ưu điểm: sử dụng các bộ truy cập được triển khai tự động khi bạn không cần làm gì khác ngoài việc lấy hoặc thiết lập trường, nhưng vẫn có tùy chọn viết mã bộ truy cập của riêng bạn mà không cần khai báo rõ ràng một trường hỗ trợ. Điều này được thực hiện bằng cách giới thiệu từ khóa field tham chiếu đến trường hỗ trợ được tạo tự động. Với tính năng mới này, ví dụ trước đó trở thành:
public int Foo
{
get;
set
{
if (value < 0) throw new ArgumentOutOfRangeException();
field = value;
OnFooChanged();
}
}
Bộ truy cập get không làm gì khác ngoài việc trả về trường, vì vậy chúng ta chỉ cần để trình biên dịch tạo ra triển khai của nó. Bộ truy cập set làm nhiều việc hơn một chút và cần truy cập trường, nhưng nó làm điều đó thông qua từ khóa field. Không còn khai báo trường rõ ràng nữa!
Sự kiện và hàm khởi tạo từng phần (Partial events and constructors)
C# 13 đã thêm thuộc tính và bộ chỉ mục từng phần, C# 14 sẽ hoàn thiện tập hợp các thành phần bạn có thể khai báo từng phần bằng cách thêm sự kiện và hàm khởi tạo.
Điều này chủ yếu hữu ích trong các kịch bản tạo mã: bạn khai báo một thành phần không có triển khai và một trình tạo mã nguồn sẽ viết triển khai cho bạn.
Thành phần mở rộng (Extension members)
Kể từ khi được giới thiệu trong C# 3, các phương thức mở rộng đã trở thành nền tảng của ngôn ngữ, cho phép mã lệnh biểu cảm và linh hoạt. Về cơ bản, chúng cho phép bạn thêm phương thức vào một kiểu mà bạn không kiểm soát và sử dụng chúng như thể chúng thực sự là các thành phần thể hiện của kiểu đó (mặc dù thực tế chúng chỉ là các phương thức tĩnh với một chút cú pháp đường).
Tuy nhiên, chúng chỉ có thể được sử dụng để thêm phương thức, không phải thuộc tính và chỉ cho một thể hiện của kiểu được mở rộng, không phải cho chính kiểu đó (tức là tĩnh). C# 14 sẽ giới thiệu một cơ chế mở rộng mới, mạnh mẽ hơn để giải quyết những hạn chế này, cho phép các phương thức và thuộc tính mở rộng thể hiện hoặc tĩnh. Cú pháp hơi khác thường, nhưng đủ linh hoạt. Nó trông như thế này:
public static class Extensions
{
// Khối mở rộng cho String
extension(string s)
{
// Phương thức mở rộng thể hiện
// Tương tự như các phương thức mở rộng cổ điển, nhưng tham số "mục tiêu"
// được khai báo trên chính khối mở rộng.
public string Capitalize() => s[..1].ToUpper() + s[1..];
}
// Khối mở rộng generic cho IEnumerable<T>
extension<T>(IEnumerable<T> source)
where T : INumber<T>
{
// Phương thức mở rộng thể hiện
public IEnumerable<T> WhereGreaterThan(T threshold)
=> source.Where(x => x > threshold);
// Thuộc tính mở rộng thể hiện
public bool IsEmpty => !source.Any();
}
// Khối mở rộng tĩnh thêm thành phần tĩnh vào List<T>
extension<T>(List<T>)
{
// Phương thức mở rộng tĩnh
public static List<T> Singleton(T value) => [value];
// Thuộc tính mở rộng tĩnh
public static List<T> Empty => [];
}
}
Tất cả các thành phần này có thể được gọi như thể chúng thực sự là thành phần của kiểu mà chúng mở rộng:
string name = GetName().Capitalize();
IEnumerable<int> items = GetItems();
if (!items.IsEmpty)
{
var largeItems = items.WhereGreaterThan(100);
...
}
var listWithSingleItem = List<int>.Singleton(42);
var emptyList = List<int>.Empty;
Tôi đã chờ đợi một tính năng như thế này trong nhiều năm, vì vậy tôi thực sự mong đợi tính năng này!
Gán có điều kiện null (Null-conditional assignment)
C# 6 đã giới thiệu toán tử có điều kiện null ?. để truy cập một thuộc tính hoặc trường trên một biểu thức chỉ khi nó không null:
Item? item = GetItem();
string? name = item?.Name; // chỉ truy cập Name nếu item không null
Tuy nhiên, điều này chỉ hoạt động trong các kịch bản “đọc”: bạn không thể gán một thành phần có điều kiện nếu biểu thức không null. Bạn vẫn phải kiểm tra rõ ràng null trước khi cố gắng gán thành phần:
Item? item = GetItem();
if (item is not null)
{
item.Name = "foo";
}
C# 14 sẽ đơn giản hóa loại kịch bản này bằng cách cho phép điều này:
Item? item = GetItem();
item?.Name = "foo"; // chỉ gán Name nếu item không null
Đó là một điều nhỏ, nhưng nó giúp mã trở nên ngắn gọn và sạch sẽ hơn.
Kết luận
Điều này kết thúc chuyến tham quan nhỏ của chúng ta về các tính năng mới chính của C# 14. Tôi hy vọng thuộc tính hỗ trợ trường và thành phần mở rộng sẽ có tác động lớn nhất, nhưng tất nhiên điều đó phụ thuộc vào trường hợp sử dụng của bạn. Nếu bạn muốn tìm hiểu về các tính năng tôi không đề cập ở đây, đây là danh sách đầy đủ.
Bạn đã có thể thử nghiệm các tính năng này bằng cách cài đặt bản phát hành ứng viên của .NET 10.



