Các tính năng mới của C# 6.0

Microsoft ra mắt C# 6.0 đi kèm với .NET Framework 4.6 và Visual Studio 2015. Bài viết này sẽ trình bày về các tính năng mới được bổ sung trong C# 6.0.

Thuộc tính tự động chỉ đọc

Thuộc tính tự động chỉ đọc (auto-property read-only) cung cấp một cú pháp ngắn gọn hơn để tạo các thuộc tính chỉ đọc. Bạn khai báo thuộc tính tự động chỉ đọc như sau:

public string FirstName { get; }
public string LastName { get; }

Các thuộc tính FirstNameLastName chỉ có thể được gán giá trị trong phương thức khởi tạo của lớp.

public Student(string firstName, string lastName)
{
    FirstName = firstName;
    LastName = lastName;
}

Cố gắng gán giá trị cho thuộc tính tự động chỉ đọc ở những phương thức khác sẽ bị lỗi khi biên dịch.

Khởi tạo thuộc tính tự động

Khởi tạo thuộc tính tự động (auto-property initializers) cho phép bạn khai báo giá trị ban đầu cho thuộc tính tự động như một phần của khai báo thuộc tính.

public ICollection<double> Grades { get; } = new List<double>();

Như vậy, ngoài cách gán giá trị cho thuộc tính tự động chỉ đọc tại phương thức khởi tạo của lớp, chúng ta có thể gán giá trị ngay khi khai báo thuộc tính.

Cú pháp thân chức năng

Cú pháp này rút gọn phần thân cho các phương thức và thuộc tính chỉ đọc. Ví dụ minh họa cho phương thức ToString():

public string FirstName { get; }
public string LastName { get; }

public override string ToString() => $"{LastName}, {FirstName}";

Bạn cũng có thể sử dụng cú pháp này cho các thuộc tính chỉ đọc:

public string FirstName { get; }
public string LastName { get; }
public string FullName => $"{FirstName} {LastName}";

using static

using static cho phép bạn sử dụng trực tiếp các thành phần tĩnh của một lớp. Bạn khai báo lớp bạn muốn sử dụng như sau:

using static System.Math;

Ví dụ minh họa using static System.Math:

using System;
using static System.Math;

public class Circle
{
   public Circle(double radius)
   {
      Radius = radius;
   }

   public double Radius { get; set; }

   public double Area
   {
      get { return PI * Pow(Radius, 2); }
   }
}

Thay vì khai báo Math.PI để sử dụng hằng số Pi và phương thức Math.Pow để tính lũy thừa thì bây giờ bạn chỉ cần khai báo PI và Pow là xong.

Toán tử ?.

Toán tử ?. sẽ kiểm tra biến có bị null hay không trước khi truy cập các thuộc tính của biến.

var first = person?.FirstName;

Như ví dụ trên, nếu biến person khác null thì nó sẽ trả về giá trị của thuộc tính FirstName, ngược lại nó sẽ trả về null.

Nếu không sử dụng toán tử ?. thì bạn phải viết code như sau để tránh bị lỗi khi biến person bị null.

if (person != null)
{
    var first = person.FirstName;
}

Nếu bạn muốn gán giá trị mặc định khi biến person null thì có thể viết như sau:

var first = person?.FirstName ?? "N/A";

Nối chuỗi

Với C# 6.0, bạn có thể sử dụng toán tử $ và cặp dấu {} để nối chuỗi nhanh chóng và trực quan. Hãy xem ví dụ sau:

var firstName = "Trung";
var lastName = "Nguyen";
var fullName = $"{firstName} {lastName}"; // -> Trung Nguyen

Bộ lọc ngoại lệ

Bộ lọc ngoại lệ được sử dụng trên khối catch bằng cách sử dụng từ khóa when và một biểu thức. Khi có ngoại lệ xảy ra, nếu biểu thức của khối catch trả về true thì khối catch mới được thực thi, ngược lại sẽ bỏ qua khối catch.

public static async Task<string> MakeRequest()
{
    WebRequestHandler webRequestHandler = new WebRequestHandler();
    webRequestHandler.AllowAutoRedirect = false;
    using (HttpClient client = new HttpClient(webRequestHandler))
    {
        var stringTask = client.GetStringAsync("https://docs.microsoft.com/en-us/dotnet/about/");
        try
        {
            var responseText = await stringTask;
            return responseText;
        }
        catch (System.Net.Http.HttpRequestException e) when (e.Message.Contains("301"))
        {
            return "Site Moved";
        }
    }
}

Biểu thức nameof

Biểu thức nameof sẽ trả về tên của một đối tượng bất kỳ. Nó giúp bạn tránh phải hard code tên của phần tử khi ghi log hoặc ném ra ngoại lệ. Bạn sẽ yêu nó rất nhiều đấy.

public Student(string firstName, string lastName)
{
    if (IsNullOrWhiteSpace(lastName))
        throw new ArgumentException(message: "Cannot be blank", paramName: nameof(lastName));
    FirstName = firstName;
    LastName = lastName;
}

await trong khối catch và finally

Với C# 6, bạn đã có thể sử dụng từ khóa await trong khối catchfinally như sau:

public static async Task<string> MakeRequestAndLogFailures()
{ 
    await LogMethodEntrance();
    var client = new System.Net.Http.HttpClient();
    var streamTask = client.GetStringAsync("https://localHost:10000");
    try 
    {
        var responseText = await streamTask;
        return responseText;
    } 
    catch (System.Net.Http.HttpRequestException e) when (e.Message.Contains("301"))
    {
        await LogError("Recovered from redirect", e);
        return "Site Moved";
    }
    finally
    {
        await LogMethodExit();
        client.Dispose();
    }
}

Khởi tạo danh sách bằng bộ chỉ mục

Bạn có thể sử dụng cú pháp khởi tạo để khởi tạo nhanh cho danh sách như sau:

private Dictionary<int, string> messages = new Dictionary<int, string>
{
    { 404, "Page not Found"},
    { 302, "Page moved, but left a forwarding address."},
    { 500, "The web server can't come out to play today."}
};

Với C# 6, bạn có thể khởi tạo danh sách sử dụng chỉ mục như sau:

private Dictionary<int, string> webErrors = new Dictionary<int, string>
{
    [404] = "Page not Found",
    [302] = "Page moved, but left a forwarding address.",
    [500] = "The web server can't come out to play today."
};


Bài viết liên quan:

Hướng dẫn này sẽ giúp bạn tìm hiểu về đọc ghi file (File I/O) trong C# và sử dụng các lớp tiện ích để đọc ghi file.

Reflection trong C#

  • 6 min read

Reflection trong C# là gì? Ứng dụng của Reflection trong C#. Cách khai báo và sử dụng Reflection trong C#.

Attribute trong C#

  • 7 min read

Attribute trong C# là gì? Có những loại attribute nào trong C#? Làm sao để sử dụng attribute trong C#.