.NET Core 3.0 (Preview 2) có gì mới?

Gần đây Microsoft cho ra mắt .NET Core 3 Preview 2. Nó bao gồm các tính năng mới cho .NET Core 3.0 và C# 8, nó cũng bao gồm luôn các tính năng mới trong Preview 1 và Preview 2. C# 8 Preview 2 là một phần của .NET Core 3 SDK, nó cũng được release cùng với Visual Studio 2019 Preview 2.

Bạn có thể download .NET Core 3 Preview 2 dành cho Windows, macOS và Linux tại đây: https://dotnet.microsoft.com/download/dotnet-core/3.0

Có thể bạn chưa biết, Microsoft đã thông báo một số tính năng lớn được xuất bản từ Preview 1 bao gồm hỗ trợ cả Winforms và WPF với .NET Core trên Windows, cả 2 framework này đều là open source. Họ cũng hỗ trợ luôn cả Entity Framework 6 trên .NET Core (xuất bản ở preview sau) ngoài ra còn các bổ sung cho Razor.

Các bạn rảnh có thể xem Release Note của .NET Core 3 Preview 2 tại đây: https://github.com/dotnet/core/blob/master/release-notes/3.0/preview/3.0.0-preview2.md

.NET Core 3 sẽ được hỗ trợ trên Visual Studio 2019, Visual Studio cho Mac và Visual Studio Code. Visual Studio 2019 Preview 2 đã được ra mắt gần đây và cũng đã hỗ trợ C# 8. Còn Visual Studio Code cũng có C# Extension vừa được hỗ trợ C# 8.

C# 8

C# 8 là bản phát hành chính của ngôn ngữ và chúng ta sẽ có một bài viết riêng nói về C# 8 tuy nhiên chúng ta sẽ nói sơ qua về nó trong bài viết này.

Using Declarations

Bạn đã mệt mỏi với các lệnh using trong ngôn ngữ C# ở đầu mỗi file code chưa? Giờ nó đã được cải tiến và bạn có thể viết lệnh khai báo cho lệnh using và có thể sử dụng trong khối lệnh của bạn, nó sẽ tự hủy đối tượng khi hết khối lệnh.

using System;
using System.Linq;
using System.Collections.Generic;
using static System.Console;
using System.IO;

namespace usingapp
{
    class Program
    {
        static void Main()
        {
            var filename = "Program.cs";
            var line = string.Empty;
            var magicString = "magicString";

            var file = new FileInfo(filename);
            using var reader = file.OpenText();
            while ((line = reader.ReadLine())!= null)
            {
                if (line.Contains(magicString))  
                { 
                    WriteLine("Found string"); 
                    return;
                }
            }

            WriteLine("String not found");
        } // reader disposed here
    }
}

Switch Expressions

Bất cứ ai dùng C# đều thích lệnh switch, nhưng không thích cú pháp của nó. C# 8 giới thiệu switch expression cho phép viết giống lamda, trong đó từ khóa switch sẽ giúp khai báo khối lệnh switch và gán giá trị cần switch vào một biến (ở đây là o):

static string Display(object o) => o switch
{
    Point { X: 0, Y: 0 }         => "origin",
    Point { X: var x, Y: var y } => $"({x}, {y})",
    _                            => "unknown"
};

Hoành tráng hơn nó còn cho chúng ta switch case theo dạng couple theo ví dụ thực tế khi chúng ta chuyển trạng thái của một object nào đó:

static State ChangeState(State current, Transition transition, bool hasKey) =>
    (current, transition) switch
    {
        (Opened, Close)              => Closed,
        (Closed, Open)               => Opened,
        (Closed, Lock)   when hasKey => Locked,
        (Locked, Unlock) when hasKey => Closed,
        _ => throw new InvalidOperationException($"Invalid transition")
    };

Ví dụ trên cho thấy bạn không cần phải định nghĩa biến hoặc một kiểu cho mỗi case. Thay vào đó trình biên dịch có thể nhận được luôn một cặp giá trị để kiểm tra cho mỗi case.

Tất cả các mẫu trên cho phép bạn viết code ngắn gọn và dễ dàng test được. Tuy nhiên vẫn có những trường hợp bạn cần sử dụng lệnh switch truyền thống, bạn có thể kết hợp cả 2.

Async streams

Tính năng này là một trong những tính năng tuyệt vời trên C# 8. Về cơ bản thì nó như thế này: Trước kia thì bạn dùng từ khóa await bạn chỉ nhận được kết quả từ hàm async 1 lần thôi. Thế nhưng giờ bạn có thể nhận về một dãy các kết quả từ hàm async. Điều này giúp bạn có thể định nghĩa ra một hàm async trả về một dãy kết quả theo vòng lặp và sử dụng từ khóa yield. Chúng ta cũng có một bài riêng về vấn đề này.

IEEE Floating-point improvements

Đầu tiên bạn phải biết chuẩn IEEE là gì đã? IEEE là có tên đầy đủ là Institute of Electrical and Electronics Engineers (IEEE) nó là chuẩn cho việc tính toán số học có dấu chấm động tức là phần thập phân. Chuẩn đầu tiên được đề ra năm 1985 (IEEE 754-1985) còn giờ đã update lên bản IEEE 754-2008. Mục tiêu là đảm bảo toàn bộ các việc tính toán trong dự án phải theo các chuẩn của IEEE.

Cái này được cải tiến trong các thư viện cho Math của .NET Core cá bạn có thể xem thêm nhưng các nội dung chính như sau:

  • Phân tích chính xác và làm tròn đầu vào có độ dài bất kỳ.
  • Phân tích chính xác và định dạng số âm.
  • Phân tích chính xác số vô tỷ và không phải số bằng cách thực hiện kiểm tra không phân biệt chữ hoa chữ thường và cho phép tùy chọn trước + khi áp dụng.

.NET Platform Dependent Intrinsics

Tính năng này bao gồm các API cho phép truy cập vào các chỉ lệnh CPU như SIMD hoặc các chỉ lệnh thao tác với Bit. Các lệnh này giúp tối ưu hiệu năng lớn trong một số trường hợp ví dụ như xử lý dữ liệu hiệu quả với lập trình song song. Các API bổ sung dành cho ứng dụng của bạn sử dụng và nó cũng giúp phong phú thêm thư viện .NET.

Danh sách một số ví dụ triển khai:

Để tìm hiểu thêm bạn có thể xem tại đây: https://github.com/dotnet/designs/blob/master/accepted/platform-intrinsics.md họ đã định nghĩa các kiến trúc hạ tầng phần cứng cho phép Microsoft và các nhà cung cấp chip xử lý đinh nghĩa và xuất ra API cho .NET.

Introducing a fast in-box JSON Writer & JSON Document

Tính năng này cho phép đọc và ghi JSON với các thư viện có sẵn trong .NET là System.Text.Json.Utf8JsonWriterSystem.Text.Json.JsonDocument. Roadmap của thư viện dành cho JSON tại đây: https://github.com/dotnet/corefx/blob/master/src/System.Text.Json/roadmap/README.md

Utf8JsonWriter

Là class cung cấp, một API hiệu năng cao, không cache chuyên chuyển hóa JSON sang text dạng unicode. Nó hỗ trợ các kiểu dữ liệu common của .NET như String, Int32 và DateTime. Thư viện này có tốc độ nhanh hơn việc sử dụng thư viện từ Json.NET.

static int WriteJson(IBufferWriter<byte> output, long[] extraData)
{
    var json = new Utf8JsonWriter(output, state: default);

    json.WriteStartObject();

    json.WriteNumber("age", 15, escape: false);
    json.WriteString("date", DateTime.Now);
    json.WriteString("first", "John");
    json.WriteString("last", "Smith");

    json.WriteStartArray("phoneNumbers", escape: false);
    json.WriteStringValue("425-000-1212", escape: false);
    json.WriteStringValue("425-000-1213");
    json.WriteEndArray();

    json.WriteStartObject("address");
    json.WriteString("street", "1 Microsoft Way");
    json.WriteString("city", "Redmond");
    json.WriteNumber("zip", 98052);
    json.WriteEndObject();

    json.WriteStartArray("ExtraArray");
    for (var i = 0; i < extraData.Length; i++)
    {
        json.WriteNumberValue(extraData[i]);
    }
    json.WriteEndArray();

    json.WriteEndObject();

    json.Flush(isFinalBlock: true);

    return (int)json.BytesWritten;
}

JsonDocument

JsonDocument được xây dựng trên Utf8JsonReader. Nó cung cấp khả năng chuyển text thành JSON và build lên DOM và hỗ trợ truy cập vào các thuộc tính. Nó có thể có tốc độ gấp 2 đến 3 lần so với Json.NET và sử dụng ít bộ nhớ hơn.

public class ArrayBufferWriter : IBufferWriter<byte>, IDisposable
{
    private byte[] _rentedBuffer;
    private int _written;

    public ArrayBufferWriter(int initialCapacity)
    {
        // TODO: argument validation

        _rentedBuffer = ArrayPool<byte>.Shared.Rent(initialCapacity);
        _written = 0;
    }

    public void Advance(int count)
    {
        // TODO: check if disposed

        // TODO: argument validation

        _written += count;
    }

    public Memory<byte> GetMemory(int sizeHint = 0)
    {
        // TODO: check if disposed

        // TODO: argument validation

        // TODO: grow/resize the buffer as needed based on your resizing strategy

        return _rentedBuffer.AsMemory(_written);
    }

    public Span<byte> GetSpan(int sizeHint = 0)
    {
        // TODO: check if disposed

        // TODO: argument validation

        // TODO: grow/resize the buffer as needed based on your resizing strategy

        return _rentedBuffer.AsSpan(_written);
    }

    public void Dispose()
    {
        // return back to the pool
    }
}

GPIO Support for Raspberry Pi

Microsoft cung cấp 2 thư iện hỗ trợ GPIO trong bản Preview 1. Và nó cũng nằm trong Preview 2, với 2 Package trên Nuget:

Các gói GPIO này bao gồm các API cho GPIO, SPI, I2C và các thiết bị PWM. Các thư viện dành cho IoT bao gồm nhiều các loại chip và cảm biến tại: https://github.com/dotnet/iot/tree/master/src/devices

Local dotnet tools

Local dotnet tools được cải tiến trong Preview 2. Tương tự như dotnet global tools nhưng nó được liên kết với một số vị trí cụ thể trên ổ đĩa. Cho phép thao tác trên từng project và từng repository. Bạn có thể đọc thêm từ bản Preview 1: https://blogs.msdn.microsoft.com/dotnet/2018/12/04/announcing-net-core-3-preview-1-and-open-sourcing-windows-desktop-frameworks/

Một số lệnh được thêm vào trong bản preview này:

  • dotnet new tool-manifest
  • dotnet tool list

Assembly Unloadability

Assembly unloadablity là một khả năng mới của AssemblyLoaderContext. Tính năng mới này rất đáng kể nhưng được ẩn đi phía API và chỉ đưa ra một số API. NÓ cho phép một load context không tải lên nữa nhằm giải phóng toàn bộ bộ nhớ đang chiếm dụng như các thể hiển, các trường static hay chính assembly. Nó giúp cho ứng dụng cho thể load hay unload các assembly thông qua cơ chế này thì ứng dụng sẽ không còn bị thiếu bộ nhớ.

Microsoft mong muốn khả năng mới này sẽ sử dụng cho các trường hợp sau:

  • Trường hợp load dynamic plugin và unload khi cần.
  • Biên dịch động, chạy và xóa code. Hữu ích cho website các scripting engine…
  • Load assembly cho việc quan sát (giống như ReflectionOnlyLoad) mặc dù MetadataLoadContext (được phát hành trên Preview1) sẽ là lựa chọn tốt cho nhiều trường hợp.

Thông tin thêm:

Windows Native Interop      

Windows có rất nhiều các thư viện native như COM, WinRT. Họ đã hỗ trợ .NET Core có thể gọi các tính năng này từ .NET Core 1.0 và thêm nhiều nữa được hỗ trợ trên .NET Core 3.0.

Một trong số đó là thư viện tương tác với Excel: https://github.com/dotnet/samples/tree/master/core/extensions/ExcelDemo

WPF and Windows Forms

Đội phát triển WPF và Winforms đã mở 2 repository là  dotnet/wpf và dotnet/winforms trên Github vào 4/12/2018 cùng ngày với ngày ra mắt của .NET Core 3.0 Preview 1.

Cũng đội phát triển này đã hoàn thiện các bước cuối cùng cho các tính năng trên .NET Framework 4.8. Các tính năng này cũng được bổ sung trên WPF và Winform trong .NET Core

Visual Studio support

Phát triển Desktop trên .NET Core 3 đòi hỏi Visual Studio 2019. Microsoft thêm vào các template cho các project Winforms và WPF khi sử dụng cửa sổ New Project Dialog. Bạn có thể tạo ứng dụng với 2 framework này mà không cần dòng lệnh.

WPF và Winform tiếp tục được phát triển và sẽ cập nhật thêm ở các bản Visual Studio sau.

MSIX Deployment for Desktop apps

MSIX là thư viện đóng gói ứng dụng Windows mới. Nó được dùng để triển khai ứng dụng .NET Core 3 trên Windows 10.

Install .NET Core 3.0 Previews on Linux with Snap

Snap được hỗ trợ cài đặt và sử dụng .NET Core trên Linux với chỉ nhân 64 bit.

Platform Support

.NET Core 3 sẽ hỗ trợ các hệ điều hành sau đây:

  • Windows Client: 7, 8.1, 10 (1607+)
  • Windows Server: 2012 R2 SP1+
  • macOS: 10.12+
  • RHEL: 6+
  • Fedora: 26+
  • Ubuntu: 16.04+
  • Debian: 9+
  • SLES: 12+
  • openSUSE: 42.3+
  • Alpine: 3.8+

Hỗ trợ cá loại chip sau đây:

  • x64 on Windows, macOS, and Linux
  • x86 on Windows
  • ARM32 on Windows and Linux
  • ARM64 on Linux

Docker image cho .NET Core 3.0 cũng có sẵn tại Docker Hub https://hub.docker.com/r/microsoft/dotnet/

Kết luận

Trên đây là sơ qua các tính năng chính có trong .NET Core 3.0 Preview nếu bạn chưa biết, bạn có thể tìm hiểu kỹ hơn từng tính năng từ các keyword ở trên.

Cảm ơn tất cả mọi người.

Lên trên