Hướng dẫn học .NET

👉 Tìm hiểu về .NET: Bạn ít nhất phải biết .NET là gì (không biết thì đọc ở đây: https://daohainam.com/2023/10/18/gioi-thieu-ve-net/), cách nó chạy chương trình như thế nào, rồi tiếp đến tìm hiểu cách viết, dịch và chạy chương trình. Ít nhất bạn phải biết bạn làm được gì với nó, cách tải và cài đặt Visual Studio (dùng hẳn bản Visual Studio nhé, đừng dùng Visual Studio Code, tập đạp xe thì cứ kiếm cái xe bình thường mà tập, đừng bắt đầu bằng xe một bánh), cách tạo project, biên dịch, chạy và debug.

Bạn có thể học .NET bằng cách theo dõi các video bài học của một tác giả có hơn 20 năm kinh nghiệm .NET tại đây: https://www.youtube.com/playlist?list=PLRLJQuuRRcFlaITD5F6XKQJxOt8QgCNAg

👉 Học ngôn ngữ lập trình: C# là ngôn ngữ chính thống nhất và đầy đủ nhất trên .NET, cú pháp đơn giản, thân thiện với người đã biết C++, Java nên học rất nhanh. Bắt đầu bằng các chương trình console, giải các bài tập đơn giản để quen với cú pháp của nó.

Bạn nên lập ra một danh sách các bài tập cần viết trước khi bắt đầu, đặt mục tiêu hoàn thành là khi bạn làm hết các bài đó. Danh sách bài tập có thể tham khảo từ các sách học ngôn ngữ khác.

Continue reading “Hướng dẫn học .NET”

Vài mẹo tối ưu trong .NET

– Ưu tiên dùng các hàm Try*: ví dụ như khi phân tích chuỗi thành số, thay vì dùng int.Parse, ta nên dùng int.TryParse, kiểm tra kết quả trả về của nó để biết việc chuyển có thành công hay không.

– Sử dụng IDictionary.TryGetValue thay vì dùng Items và bắt Exception.

– Sử dụng ArgumentNullException.ThrowIfNull() thay vì if (v == null) throw new ArgumentNullException().

– Sử dụng ArgumentOutOfRangeException.ThrowIf* thay vì if () throw new ArgumentOutOfRangeException().

– Khi cần một IEnumerable rỗng, hãy sử dụng Enumerable.Empty<T>() thay vì new List<T>(), tương tự cho Array.Empty.

– Trong khối catch (Exception ex), bạn có thể dùng throw; để throw lại ex mà vẫn giữ stack trace, nếu bạn gọi throw ex; thì stack trace sẽ được tạo lại từ nơi bạn gọi.

– Các object hay dùng nên được “cache” lại bằng cách sử dụng các static instance.

– Từ khóa stackalloc sẽ giúp bạn khai báo một biến trên stack thay vì trên heap, sử dụng nó rất tốt với các biến kích thước nhỏ trong các hàm được gọi nhiều, nhưng cũng phải cẩn trọng nếu hàm của bạn được gọi đệ quy vì nó dễ gây stack overflow. Bạn cũng cần tránh khai báo nó bên trong vòng lặp vì lý do tương tự.

* Exception là một thứ ‘đắt đỏ’ trong .NET, nó phải thu thập nhiều thông tin như stack trace, thông tin mã nguồn…, vì vậy không nên lạm dụng. Ta chỉ nên sử dụng new Exception trong những trường hợp thực sự là ngoại lệ, hiếm gặp.

* Quá trình dọn rác trên heap tiêu tốn rất nhiều tài nguyên, vậy nên càng ít tạo object mới càng tốt.

Từ khóa yield trong C#

Hôm trước mình có một câu hỏi liên quan đến từ khóa yield (https://www.facebook.com/namdotnet/posts/pfbid02ghwNXv2WCxka7BUyYv4pW7jHJjzQrT1qNSZaLE3oWvv8dCWpjWc7jSS91L2UB78wl), sở dĩ mình nhắc đến từ khóa này vì nó liên quan đến khái niệm State Machine (máy trạng thái), cũng là một khái niệm được dùng để tạo nên async/await.

Lưu ý: đã có clip chi tiết về async/await

Continue reading “Từ khóa yield trong C#”

Giới thiệu về .NET

Đây là bài viết giới thiệu về .NET, một platform mạnh mẽ, hỗ trợ đa nền tảng, nhiều công cụ hỗ trợ, và cũng rất phổ biến trong thị trường lao động.

👉 Một chút lịch sử:

– Microsoft đã từng hỗ trợ Java. Bộ Visual Studio 6.0 đã từng có một công cụ tên Visual J++ dùng để viết app Java, sau này còn có trình biên dịch Visual J# để dịch ứng dụng viết bằng Java trên .NET.

– Microsoft bắt đầu phát triển .NET (hay còn gọi là .NET Framework) như một nền tảng thay thế Java khi mối quan hệ với Sun Microsystems (chủ sở hữu Java lúc đó) rạn nứt.

– Nhiều ứng dụng của Microsoft đã được viết lại trên .NET, bao gồm cả IDE Visual Studio và CSDL SQL Server, đồng thời trình runtime .NET cũng được tích hợp sẵn vào Windows luôn.

– Tuy về mặt lý thuyết .NET được thiết kế để chạy trên mọi nền tảng, tuy nhiên Microsoft chỉ phát triển bộ runtime cho Windows, do vậy các app .NET chỉ có thể chạy trên Windows.

– Mono project được cộng đồng mã nguồn mở phát triển để xây dựng trình runtime cho .NET trên Linux, và sau này mở rộng ra cả các nền tảng khác. Mono không hỗ trợ đầy đủ các công nghệ như .NET Framework chạy trên Windows.

– Sau một hồi mua đi bán lại thì công ty chủ quản tạo ra Mono có ý đồ dẹp tiệm dự án này, anh chàng LTV đã tạo nên Mono bèn lập ra một công ty mới là Xamarin, tiếp tục phát triển các công nghệ hỗ trợ xây dựng trình runtime cho .NET trên các nền tảng ngoài Windows, thậm chí mở rộng ra cho cả iOS và Android.

– Xamarin phát hành bộ công cụ xây dựng ứng dụng .NET cho đa nền tảng tên là Xamarin Studio.

– Microsoft mua lại Xamarin và mang các công nghệ từ Xamarin Studio tích hợp vào Visual Studio. Một trang sử mới mở ra khi các công cụ này được cung cấp miễn phí thay vì trả phí khá đắt đỏ, người người nhà nhà thi nhau viết app .NET cho smart phone, hơn 1 tỷ developer đã chuyển từ Java/C/C++/Swift sang C# (*).

– Nhận thấy .NET Framework đã trở nên cũ kỹ, đồng thời nhu cầu phát triển ứng dụng trên các nền tảng ngoài Windows (Linux, Mac, iOS, Android…) rất cao. Việc hỗ trợ đồng thời nhiều trình runtime tương thích .NET Framework khác nhau vừa tốn kém chi phí vừa bất tiện, Microsoft phát triển một nền tảng mới gọi là .NET Core.

– .NET Core là một bản .NET được thiết kế và xây dựng lại, với mục tiêu đa nền tảng ngay từ đầu.

– Có rất nhiều dự án vốn viết trên .NET Framework nay muốn chuyển sang .NET Core, tuy nhiên rất khó và cũng rất rủi ro khi chuyển toàn bộ từ nền tảng cũ sang nền tảng mới, vậy nên Microsoft đưa ra thêm một thứ gọi là .NET Standard.

– .NET Standard chỉ là các chuẩn tương thích, không phải là một trình runtime hay framework. Ví dụ .NET Framework 4.6.1+ và .NET Core 2.0+ tương thích với .NET Standard 2.0, do vậy bạn hoàn toàn có thể sử dụng các thư viện được viết ra cho .NET Standard 2.0 trong các chương trình viết cho Framework 4.6.1 lẫn .NET Core 2.0. Nhờ vậy các phần mềm cũ có thể được chuyển đổi dần mà không cần chuyển hoàn toàn sang .NET Core.

– Phiên bản chính cuối cùng của .NET Framework là 4, được phát hành vào 2010, phiên bản hiện tại là 4.8.1, đây cũng sẽ là bản .NET Framework cuối cùng. (**)

– .NET Core có các phiên bản 1, 2 và 3, sau bản 3.0 thì nhảy luôn lên 5. .NET Core không có phiên bản 4 vì sợ nhầm lẫn với .NET Framework 4, vốn là phiên bản phổ biến đến mức trước đây nhiều người hay gọi là .NET 4.0.

– Từ phiên bản 5.0, .NET Core cũng bỏ luôn chữ Core và ta chỉ còn gọi là .NET. Vì không có phiên bản .NET Framework nào >= 5 nên người ta không còn sợ nhầm lẫn nữa.

– Phiên bản chính thức hiện tại là .NET 7, phiên bản 8 sẽ ra mắt vào cuối năm nay. Theo kế hoạch thì cứ một năm sẽ có một phiên bản mới.

– Vì .NET Framework đã ngừng phát triển nên từ giờ trở đi khi nói về .NET, ta sẽ mặc nhiên là nói về .NET mới.

👉 Vậy .NET làm được gì?

– .NET có thể được dùng để viết gần như tất cả các loại ứng dụng, ngoại trừ các ứng dụng hệ thống.

– Bạn có thể viết web, mobile app, ứng dụng desktop, chạy trên local, chạy trên cloud, viết game… Nói tóm lại là trừ khi viết firmware, OS hay driver… còn lại thì bạn đều có thể làm được với .NET.

👉 Có gì lưu ý khi học .NET?

– .NET chỉ là một framework, bạn có thể lập trình bằng bất kỳ ngôn ngữ nào miễn sao nó có trình biên dịch tương thích. Tuy nhiên C# là ngôn ngữ được Microsoft hỗ trợ mạnh nhất và vẫn liên tục được cập nhật, vì vậy học viết app .NET bằng C# được coi là chuẩn mực.

– C# có cấu trúc giống với Java, vậy nên ai đã từng học C++/Java chuyển sang sẽ thấy rất quen thuộc (đó là lý do tại sao tôi luôn khuyên những người mới học nên bắt đầu với C++ – khổ trước sướng sau). Tuy nhiên để nắm chắc C# sẽ mất khá nhiều thời gian vì nó có nhiều thành phần hỗ trợ runtime (async, lock, LINQ…).

– Ứng dụng .NET có thể được dịch trên một nền tảng và chạy trên một nền tảng khác. Chương trình của bạn sẽ được dịch sang mã IL, sau đó sẽ được dịch tiếp một lần nữa sang mã máy khi chạy (JiT), các bản .NET mới còn cho phép dịch sẵn sang mã máy khi cài đặt ứng dụng (AoT), nhờ đó tốc độ khởi động ứng dụng sẽ nhanh hơn.

– Bộ nhớ trong .NET được quản lý tự động, bạn không cần giải phóng vùng nhớ đã cấp phát.

– Tôi khuyên dùng Visual Studio bản mới nhất nếu có thể, bạn sẽ mất một thời gian làm quen nhưng khi đã quen rồi thì bạn sẽ hiểu vì sao nó là IDE hàng đầu thế giới. Dù gì sẽ có lúc bạn phải làm quen với nó nếu theo .NET.

– .NET (Core) là mã nguồn mở, .NET Framework cũng mở mã nguồn nhưng chỉ cho mục đích tham khảo.

👉 Có nhiều công ty tuyển dụng .NET không?

Bạn tự vào các trang tuyển dụng tìm hiểu đi! Ở đây không trả lời mấy câu này!

Bài 12: Tổng kết

Chúng tôi có một số phiên bản trong kỷ nguyên .NET hiện đại, gần đây đã phát hành .NET 7. Chúng tôi nghĩ rằng sẽ hữu ích nếu chúng tôi tóm tắt những gì đang cố gắng xây dựng — ở mức thấp nhất của nền tảng — kể từ .NET Core 1.0 . Mặc dù rõ ràng chúng tôi đã giữ nguyên tinh thần của .NET gốc, nhưng kết quả là một nền tảng mới tạo ra một con đường mới và mang lại nhiều giá trị mới hơn đáng kể cho các nhà phát triển.

Hãy kết thúc nơi chúng ta bắt đầu. .NET là đại diện cho bốn giá trị: Năng suất, Hiệu suất, Bảo mật và Độ tin cậy. Chúng tôi rất tin tưởng rằng các nhà phát triển sẽ được phục vụ tốt nhất khi các nền tảng ngôn ngữ khác nhau cung cấp các cách tiếp cận khác nhau. Với tư cách là một nhóm, chúng tôi tìm cách mang lại năng suất cao nhất cho các nhà phát triển .NET đồng thời cung cấp một nền tảng dẫn đầu về hiệu suất, bảo mật và độ tin cậy.

Chúng tôi dự định thêm nhiều bài viết trong loạt bài này. Những chủ đề nào bạn muốn xem giải quyết đầu tiên? Hãy cho chúng tôi biết trong các ý kiến. Bạn có muốn xem thêm nội dung về “bức tranh lớn” này không?

Nếu muốn biết thêm nội dung này, bạn có thể xem phần Giới thiệu về Common Language Runtime (CLR).

Bài đăng này được viết bởi Jan Kotas, Rich Lander, Maoni Stephens và Stephen Toub, với thông tin chi tiết và đánh giá của các đồng nghiệp trong nhóm .NET.

(Kết thúc bài viết)

Bài viết gốc tại địa chỉ: https://devblogs.microsoft.com/dotnet/why-dotnet/

Bài 11: Các bản phân phối

Nhóm .NET tại Microsoft duy trì một số bản phân phối, gần đây nhất đã hỗ trợ Android, iOS, và WebAssembly. Nhóm này dùng một số kỹ thuật khác nhau để duy trì hỗ trợ cho các yêu cầu riêng biệt của từng môi trường. Hầu hết các nền tảng được viết bằng C#, cho phép khi chuyển đổi chỉ cần làm việc trên một tập tương đối nhỏ các thành phần.

Cộng đồng cũng duy trì một tập các bản phân phối khác, chủ yếu tập trung cho Linux. Ví dụ, .NET được bao gồm trong Alpine LinuxFedoraRed Hat Enterprise Linux, và Ubuntu.

Cộng đồng cũng đã mở rộng .NET để chạy trên các nền tảng khác. Samsung đã chuyển .NET lên nền tảng Tizen cho ArmRed Hat và IBM cũng chuyển .NET lên LinuxONE/s390xLoongson Technology chuyển .NET lên LoongArch. Chúng tôi hi vọng và mong muốn sẽ có thêm nhiều đối tác nữa chuyển .NET lên các môi trường khác.

Continue reading “Bài 11: Các bản phân phối”

Bài 10: Interop

.NET đã được thiết kế rõ ràng để tương tác với các thư viện native với chi phí thấp. Các chương trình và thư viện .NET có thể gọi các API hệ điều hành cấp thấp một cách liền mạch hoặc khai thác hệ sinh thái rộng lớn của các thư viện C/C++. Thời gian chạy .NET hiện đại tập trung vào việc cung cấp các khối xây dựng tương tác cấp thấp, chẳng hạn như khả năng gọi các native method thông qua các con trỏ hàm, xuất các phương thức .NET dưới dạng unmanaged callbacks hoặc customized interface casting. .NET cũng liên tục phát triển trong lĩnh vực này và trong .NET 7 đã phát hành các giải pháp tạo mã nguồn giúp giảm thêm chi phí hoạt động và thân thiện với AOT.

Đoạn mã sau minh họa hiệu quả của các con trỏ hàm C#.

// Using a function pointer avoids a delegate allocation.
// Equivalent to `void (*fptr)(int) = &Callback;` in C
delegate* unmanaged<int, void> fptr = &Callback;
RegisterCallback(fptr);

[UnmanagedCallersOnly]
static void Callback(int a) => Console.WriteLine($"Callback:  {a}");

[LibraryImport("...", EntryPoint = "RegisterCallback")]
static partial void RegisterCallback(delegate* unmanaged<int, void> fptr);

Ví dụ này sử dụng trình tạo mã nguồn LibraryImport được giới thiệu trong .NET 7. Nó dựa trên DllImport hoặc P/Invoke hiện có.

Continue reading “Bài 10: Interop”

Bài 9: Khả năng sinh code

Mã bytecode .NET không phải là định dạng có thể thực thi trực tiếp bởi máy tính, mà nó cần phải được xử lý bằng một số dạng trình tạo code. Điều này có thể đạt được bằng cách biên dịch sẵn(AOT), biên dịch, phiên dịch hoặc biên dịch ngay lúc chạy (JIT). Trên thực tế, hiện nay tất cả cách cách này đều được sử dụng trong các tình huống khác nhau.

.NET được biết đến nhiều nhất với trình biên dịch JIT. Các JIT biên dịch các phương thức (và các thành phần khác) thành native code trong khi ứng dụng đang chạy và chỉ khi chúng cần thiết, do đó có tên “just in time” (đúng lúc). Ví dụ: một chương trình có thể chỉ gọi một trong số các phương thức trên một kiểu khi chạy. Một JIT cũng có thể tận dụng thông tin chỉ có sẵn trong thời gian chạy, như giá trị của các biến tĩnh chỉ đọc đã được khởi tạo hoặc mô hình CPU chính xác mà chương trình đang chạy và có thể biên dịch cùng một phương thức nhiều lần để tối ưu hóa mỗi lần cho các mục đích khác nhau với khả năng tối ưu code dựa trên các bài học từ các lần biên dịch trước đó.

Continue reading “Bài 9: Khả năng sinh code”

Bài 8: Định dạng được biên dịch của mã nhị phân

Các ứng dụng và thư viện được biên dịch thành mã bytecode đa nền tảng được tiêu chuẩn hóa ở định dạng PE/COFF. Bản phân phối ở dạng nhị phân là một tính năng được thiết cho hiệu suất. Nó cho phép các ứng dụng mở rộng quy mô cho số lượng dự án ngày càng lớn hơn. Mỗi thư viện bao gồm một tập dữ liệu gồm danh sách các kiểu được import và export, còn được gọi là metadata, đóng vai trò quan trọng cho cả hoạt động phát triển và chạy ứng dụng.

Các bản dữ liệu nhị phân được biên dịch bao gồm hai phần chính:

  • Mã bytecode — định dạng ngắn gọn và thông thường cho phép bỏ qua nhu cầu phân tích cú pháp từ mã nguồn dạng văn bản sau khi biên dịch bởi một trình biên dịch ngôn ngữ cấp cao (như C#).
  • Metadata — mô tả các kiểu được import và export, bao gồm vị trí của mã bytecode cho một phương thức nhất định.
Continue reading “Bài 8: Định dạng được biên dịch của mã nhị phân”

Bài 7: Reflection

Reflection là một mô hình “chương trình như dữ liệu”, cho phép một phần của chương trình truy vấn và gọi các phần khác một cách “động”, như là các assembly, kiểu dữ liệu hoặc các thành phần của kiểu. Nó đặc biệt hữu dụng với các mô hình lập trình late-bound(1) và các công cụ.

Đoạn code sau sử dụng reflection để tìm và gọi các kiểu:

foreach (Type type in typeof(Program).Assembly.DefinedTypes)
{
    if (type.IsAssignableTo(typeof(IStory)) &&
        !type.IsInterface)
    {
        IStory? story = (IStory?)Activator.CreateInstance(type);
        if (story is not null)
        {
            var text = story.TellMeAStory();
            Console.WriteLine(text);
        }
    }
}

interface IStory
{
    string TellMeAStory();
}

class BedTimeStore : IStory
{
    public string TellMeAStory() => "Once upon a time, there was an orphan learning magic ...";
}

class HorrorStory : IStory
{
    public string TellMeAStory() => "On a dark and stormy night, I heard a strange voice in the cellar ...";
}
Continue reading “Bài 7: Reflection”