Khác với các phiên bản C# trước đây - mỗi phiên bản chỉ phát hành một lần duy nhất. Kể từ phiên bản C# 7 Microsoft đã có những thay đổi để tăng tốc độ phát hành.
Sau khi phát hành phiên bản chính là C# 7.0, Microsoft tiếp tục phát hành thêm các phiên bản như C# 7.1, C# 7.2 và C# 7.3 để bổ sung thêm các tính năng mới.
Nếu bạn bỏ lỡ bài viết về các tính năng mới của C# 7.0 thì có thể xem tại đây:
C# 7.1 là bản phát hành bổ sung đầu tiên cho ngôn ngữ C#. Nó đánh dấu một nhịp phát hành nhanh cho ngôn ngữ.
Bạn có thể sử dụng các tính năng mới sớm hơn, lý tưởng nhất là mỗi khi có tính năng mới đã sẵn sàng.
C# 7.1 thêm khả năng cấu hình trình biên dịch để khớp với phiên bản ngôn ngữ đã chỉ định. Điều đó cho phép bạn tách việc nâng cấp các công cụ phát triển ra khỏi việc nâng cấp các phiên bản ngôn ngữ.
C# 7.1 thêm thành phần cấu hình lựa chọn phiên bản ngôn ngữ, ba tính năng ngôn ngữ mới và hành vi trình biên dịch mới.
Các tính năng ngôn ngữ mới trong phiên bản này là:
Main
không đồng bộ.default
.tuple
.Phương thức Main không đồng bộ cho phép bạn sử dụng await
trong phương thức Main
của mình. Trước đây bạn sẽ cần phải viết:
static int Main()
{
return DoAsyncWork().GetAwaiter().GetResult();
}
Bây giờ bạn có thể viết:
static async Task<int> Main()
{
// This could also be replaced with the body
// DoAsyncWork, including its await expressions:
return await DoAsyncWork();
}
Nếu chương trình của bạn không trả về mã thoát (exit code), bạn có thể khai báo một phương thức Main
trả về Task
như sau:
static async Task Main()
{
await SomeAsyncMethod();
}
default
Trước đây bạn sẽ sử dụng biểu thức default
để khai báo giá trị mặc định như sau:
Func<string, bool> whereClause = default(Func<string, bool>);
Bây giờ bạn có thể bỏ qua phần khai báo kiểu dữ liệu ở phía bên phải của khởi tạo giá trị mặc định như sau:
Func<string, bool> whereClause = default;
tuple
Tính năng này là một cải tiến nhỏ cho tuple được giới thiệu trong C# 7.0. Nhiều khi bạn khởi tạo một tuple, các biến được sử dụng cho phía bên phải của phép gán giống như tên bạn muốn cho các phần tử tuple như sau:
int count = 5;
string label = "Colors used in the map";
var pair = (count: count, label: label);
Trong C# 7.1 tên của các phần tử tuple có thể được suy ra từ các biến được sử dụng để khởi tạo tuple:
int count = 5;
string label = "Colors used in the map";
var pair = (count, label); // element names are "count" and "label"
Bắt đầu từ phiên bản C# 7.1, khớp mẫu cho biểu thức is
và switch
hỗ trợ tham số kiểu generic. Điều này rất hữu ích khi kiểm tra các kiểu struct
hoặc class
và bạn muốn tránh việc sử dụng boxing và unboxing.
C# 7.2 là một bản phát hành bổ sung khác có thêm một số tính năng hữu ích. Phiên bản này hoạt động hiệu quả hơn với các kiểu giá trị bằng cách tránh các bản sao hoặc phân bổ bộ nhớ không cần thiết.
Các tính năng ngôn ngữ mới trong phiên bản C# 7.2 là:
private protected
ref
Các tính năng ngôn ngữ được giới thiệu trong phiên bản C# 7.2 cho phép bạn làm việc với các kiểu giá trị trong khi sử dụng như kiểu tham chiếu.
Chúng được thiết kế để tăng hiệu suất bằng cách giảm thiểu việc sao chép các kiểu giá trị mà không phát sinh phân bổ bộ nhớ liên quan đến việc sử dụng các kiểu tham chiếu. Các tính năng bao gồm:
in
cho các tham số để chỉ định rằng một đối số được truyền bằng tham chiếu nhưng không được thay đổi giá trị trong phương thức.ref
. C# 7.2 bổ sung thêm cho tính năng này đó là sử dụng khai báo ref readonly
trên phương thức để chỉ ra rằng phương thức trả về giá trị của nó bằng tham chiếu nhưng không cho phép ghi vào đối tượng đó.readonly struct
để cho biết rằng một struct là không thay đổi và có thể được sử dụng làm một tham số in
cho phương thức.ref struct
để cho biết rằng một struct không thể là thành viên của một lớp hoặc được sử dụng ở những nơi mà nó có thể được phân bổ trên bộ nhớ heap. Một ref struct
phải luôn luôn được phân bổ trên bộ nhớ stack.Từ C# 7.2 bạn có thể gọi phương thức với các đối số được đặt tên ở vị trí bất kỳ, không cần phải tuân theo thứ tự được khai báo trong phương thức.
class NamedExample
{
static void Main(string[] args)
{
// The method can be called in the normal way, by using positional arguments.
PrintOrderDetails("Gift Shop", 31, "Red Mug");
// Named arguments can be supplied for the parameters in any order.
PrintOrderDetails(orderNum: 31, productName: "Red Mug", sellerName: "Gift Shop");
PrintOrderDetails(productName: "Red Mug", sellerName: "Gift Shop", orderNum: 31);
// Named arguments mixed with positional arguments are valid
// as long as they are used in their correct position.
PrintOrderDetails("Gift Shop", 31, productName: "Red Mug");
PrintOrderDetails(sellerName: "Gift Shop", 31, productName: "Red Mug"); // C# 7.2 onwards
PrintOrderDetails("Gift Shop", orderNum: 31, "Red Mug");
}
static void PrintOrderDetails(string sellerName, int orderNum, string productName)
{
if (string.IsNullOrWhiteSpace(sellerName))
{
throw new ArgumentException(message: "Seller name cannot be null or empty.", paramName: nameof(sellerName));
}
Console.WriteLine($"Seller: {sellerName}, Order #: {orderNum}, Product: {productName}");
}
}
C# 7.0 không hỗ trợ sử dụng ký tự _
để tách các chữ số. Tuy nhiên từ C# 7.2 đã hỗ trợ như ví dụ dưới đây:
// decimal notation
var balance = 2_435_951.68;
// hexadecimal notation
var num = 0x01_00;
// binary notation
int binaryValue = 0b_0101_0101;
Một chỉ thị truy cập hỗn hợp mới: private protected
chỉ ra rằng một thành viên có thể được truy cập bằng cách chứa các lớp hoặc các lớp dẫn xuất được khai báo trong cùng một assembly.
Trong khi protected internal
cho phép truy cập bởi các lớp dẫn xuất hoặc các lớp trong cùng một assembly, private protected
giới hạn truy cập vào các kiểu dẫn xuất được khai báo trong cùng một assembly.
Cuối cùng, biểu thức điều kiện có thể tạo ra kết quả ref
thay vì kết quả giá trị. Ví dụ: bạn có thể viết như sau để lấy tham chiếu đến phần tử đầu tiên trong một trong hai mảng:
ref var r = ref (arr != null ? ref arr[0] : ref otherArr[0]);
Biến r
là một tham chiếu đến giá trị đầu tiên trong một arr
hoặc otherArr
.
Ở bản phát hành C# 7.3, Microsoft đã cung cấp các tính năng mã an toàn có thể hoạt động như mã không an toàn (unsafe code) và các cải tiến cho các tính năng hiện có.
Ở phần này mình chỉ tập trung vào những cải tiến cho các tính năng hiện có:
==
và toán tử !=
.in
.==
và toán tử !=
Bắt đầu với C# 7.3, tuple hỗ trợ các toán tử ==
và toán tử !=
. Các toán tử này hoạt động bằng cách so sánh từng thành viên của đối số bên trái với từng thành viên của đối số bên phải theo thứ tự. Chúng sẽ ngừng đánh giá các thành viên ngay khi một cặp không bằng nhau. Ví dụ:
var left = (a: 5, b: 10);
var right = (a: 5, b: 10);
Console.WriteLine(left == right); // displays 'true'
(int a, int b)? nullableTuple = right;
Console.WriteLine(left != nullableTuple); // displays 'false'
Trường sao lưu tự động là trường được trình biên dịch tạo ra cho thuộc tính được triển khai tự động (auto-implemented properties). Chúng ta sẽ không thấy được các trường sao lưu này.
Bắt đầu từ C# 7.3, các attribute có thể được gắn vào trường sao lưu được tạo bởi trình biên dịch cho các thuộc tính được triển khai tự động.
Ví dụ, lớp Person
có một thuộc tính được triển khai tự động là Id
, nhưng thiết kế của bạn không yêu cầu duy trì thuộc tính Id
. NonSerializedAttribute chỉ có thể được sử dụng cho các trường, không sử dụng cho thuộc tính.
Bạn có thể đính kèm NonSerializedAttribution vào trường sao lưu cho thuộc tính Id
bằng cách sử dụng khai báo field:
trên thuộc tính, như trong ví dụ sau:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
[field:NonSerialized]
public int Id { get; set; }
public string FullName => $"{FirstName} {LastName}";
}
in
Khi từ khóa in
được thêm vào đối số, hai phương thức này sẽ gây ra sự mơ hồ:
static void M(S arg);
static void M(in S arg);
Bây giờ, để gọi phiên bản với đối số tham chiếu chỉ đọc (dòn thứ hai), bạn phải sử dụng từ khóa in
khi gọi phương thức.
Cú pháp khai báo biến out
được thêm vào trong C# 7.0 đã được mở rộng cho trình khởi tạo trường, trình khởi tạo phương thức và phương thức khởi tạo và mệnh đề truy vấn. Nó cho phép mã như ví dụ sau:
public class B
{
public B(int i, out int j)
{
j = i;
}
}
public class D : B
{
public D(int i) : base(i, out var j)
{
Console.WriteLine($"The value of 'j' is {j}");
}
}
Bạn có thể vui lòng tắt trình chặn quảng cáo ❤️ để hỗ trợ chúng tôi duy trì hoạt động của trang web.
Trong loạt bài này, tôi sẽ xem xét một số
Ngôn ngữ C# đã bật các bộ tăng áp liên
Trong bài viết này, chúng ta sẽ tìm hiểu lớp tiện ích ZipFile trong C#, cách nén tập tin và thư mục, cùng với giải nén tập tin zip.
Bài viết này sẽ giới thiệu cách đơn giản nhất mà tôi đã tìm thấy để đọc và ghi file Excel bằng C# sử dụng ExcelMapper.