Cách viết hàm tạo khi kiến thiết xây dựng class trong C#

Constructor ( hàm tạo / hàm dựng ) là một loại thành viên đặc biệt quan trọng trong class C #. Nhiệm vụ của nó là khởi tạo object của class. Mỗi khi gọi lệnh khởi tạo, thực tiễn là bạn đang gọi tới constructor. Bài học này của mindovermetal sẽ hướng dẫn bạn cách viết hàm tạo khi kiến thiết xây dựng class và một vài cách khởi tạo đối tượng người tiêu dùng cho class trong C#

Constructor trong C # và khởi tạo object

Các class bạn xây dựng trong các bài học trước tự bản thân nó không có nhiều giá trị với chương trình bởi vì class chỉ đơn thuần là mô tả kiểu dữ liệu. Để sử dụng class trong chương trình C#, bạn cần khởi tạo đối tượng của nó.

Khởi tạo đối tượng người dùng trong C # là quy trình nhu yếu tạo ra một object của class tương ứng trên vùng nhớ heap và lấy địa chỉ của object gán cho một biến .Sau khi object được khởi tạo, bạn hoàn toàn có thể truy xuất những thành viên của nó để Giao hàng cho mục tiêu của chương trình .

cach-viet-ham-tao-khi-kien-thiet-xay-dung-class-trong-c-1-mindovermetal

Để khởi tạo object trong C# sử dụng từ khóa new và lời gọi tới một trong số các hàm tạo (constructor) của class tương tự như đối với struct.

Xây dựng constructor cho class C #

Hàm tạo, về mặt hình thức, luôn có cùng tên với class và không có kiểu ra. Danh sách tham số và thân hàm tựa như như những phương pháp thành viên .Hãy cùng thực thi ví dụ sau để hiểu cách thiết kế xây dựng hàm tạo của class .Tạo một blank solution S08_ObjectInstantiation rồi thêm project P01_DefaultConstructor. Viết code cho Program. cs như sau :

namespace P01_DefaultConstructor
{
    using static System.Console;

    internal class Book
    {
        private string _authors;
        private string _title;
        private int _year;
        private string _publisher;

        public Book() // đây là một hàm tạo của class Book
        {
            _authors = "Unknown author";
            _title = "A new book";
            _publisher = "Unknown publisher";
            _year = 2019;
        }

        public Book(string author, string title, int year, string publisher) // đây là hàm tạo có tham số
        {
            _authors = author;
            _title = title;
            _year = year;
            _publisher = publisher;
        }

        public string Print()
        {
            return $"{_authors}, \"{_title}\", -{_publisher}, {_year}";
        }
    }

    internal class Program
    {
        private static void Main(string[] args)
        {           

            ReadKey();
        }
    }
}

Trong ví dụ trên bạn đã thiết kế xây dựng một class Book đơn thuần. Trong class này chỉ có 4 biến thành viên private ( _authors, _title, _year, _publisher ), 1 phương pháp thành viên Print ( ) .Bạn hoàn toàn có thể chú ý hai thành viên đặc biệt quan trọng :

public Book() // đây là một hàm tạo của class Book
{
    _authors = "Unknown author";
    _title = "A new book";
    _publisher = "Unknown publisher";
    _year = 2019;
}

public Book(string author, string title, int year, string publisher) // đây là hàm tạo có tham số
{
    _authors = author;
    _title = title;
    _year = year;
    _publisher = publisher;
}

Đây là hai constructor của class Book. Khi khởi tạo object với lệnh new, thực tế bạn sẽ gọi tới một trong hai constructor này. Đây cũng là khối code đầu tiên được thực thi khi khởi tạo object.

Mỗi constructor hoàn toàn có thể chứa một access modifier ( public, private, protected ) như những thành viên khác. Điều đặc biệt quan trọng là tên của constructor phải trùng với tên class. Phía sau tên của constructor là list tham số, tựa như như so với phương pháp .Với vai trò đó, trong constructor thường đặt những lệnh để khởi tạo giá trị cho những thành viên ( như bạn đã làm ) .

cach-viet-ham-tao-khi-kien-thiet-xay-dung-class-trong-c-2-mindovermetal

Trong mỗi class C# không giới hạn số lượng constructor. Tuy nhiên, các constructor không được phép có danh sách tham số trùng nhau. Nếu có nhiều constructor trong một class, mỗi constructor được gọi là một overload (nạp chồng hàm tạo).

Danh sách tham số được gọi là trùng nhau nếu thứ tự những tham số theo kiểu ( không theo tên gọi ) và số lượng tham số giống nhau. Bạn sẽ quay lại yếu tố này khi học về nạp chồng phương pháp và delegate .Bạn hoàn toàn có thể chú ý hàm tạo và phương pháp được Visual Studio hiển thị với cùng một hình tượng .Visual Studio sử dụng snippet ctor để sinh đoạn code khung cho hàm tạo .

Khởi tạo object với constructor

Bây giờ trong phương pháp Main hãy viết 1 số ít lệnh như sau :

private static void Main(string[] args)
{
    var book1 = new Book();
    WriteLine(book1.Print());

    var book2 = new Book("Christian Nagel", "Professional C# 7 and the .NET core 2.0", 2018, "Wrox");
    WriteLine(book2.Print());

    ReadKey();
}

Trong đó ,

var book1 = new Book();
var book2 = new Book("Christian Nagel", "Professional C# 7 and the .NET core 2.0", 2018, "Wrox");

là hai lệnh khởi tạo object của lớp Book, sử dụng hai constructor đã xây dựng.

Như vậy hoàn toàn có thể thấy, lệnh khởi tạo object cần có từ khóa new và gọi tới một trong số những constructor của class. Kết quả khởi tạo hoàn toàn có thể gán cho một biến để sau tái sử dụng .

Khởi tạo object với property

C # phân phối một cách khởi tạo object khác : sử dụng bộ khởi tạo ( object initializer ). Cú pháp khởi tạo này sử dụng property và được đưa vào từ C # 3 (. NET framework 3.5 ) .Hãy cùng thực thi một ví dụ trước .Thêm những property sau vào class Book :

public string Authors { get => _authors; set => _authors = value; }
public string Title { get => _title; set => _title = value; }
public int Year { get => _year; set => _year = value; }

Trong phương pháp Main bổ trợ những lệnh sau :

var book3 = new Book
 {
     Authors = "Christian Nagel",
     Title = "Professional C# 7 and the .NET core 2.0",
     Year = 2018
 };
 WriteLine(book3.Print());

Đây là cách khởi tạo với object initializer sử dụng property .Trong cách khởi tạo này, tất cả chúng ta vẫn sử dụng lời gọi tới hàm tạo như thông thường, tuy nhiên, tất cả chúng ta hoàn toàn có thể tích hợp luôn việc gán giá trị cho những property trong cùng lệnh khởi tạo theo quy tắc :

  • Tất cả lệnh gán giá trị cho property phải đặt trong cặp dấu ngoặc nhọn;
  • Mỗi lệnh gán viết tách nhau bởi một dấu phẩy;
  • Phải kết thúc bằng dấu chấm phẩy, vì đây thực chất là một lệnh, không phải một khối lệnh (code block) như bình thường;
  • Không bắt buộc phải gán giá trị cho tất cả các thuộc tính.

Cách thức khởi tạo này đặc biệt quan trọng tương thích với những class chứa tài liệu sử dụng property cũng như khởi tạo list. Hãy tưởng tượng nếu không có phương pháp khởi tạo này, hàm tạo phải có rất nhiều tham số đầu vào để hoàn toàn có thể gán giá trị cho tổng thể những thành viên. Một hàm tạo với list tham số quá dài nhìn rất cồng kềnh, khó nhớ thứ tự những tham số, cũng như dễ gây lỗi khi truyền tham số .Nếu sử dụng hàm tạo mặc định hoặc hàm tạo không tham số hoàn toàn có thể bỏ cả cặp dấu ngoặc tròn sau tên constructor .

Một số yếu tố khác với constructor trong C #

Default constructor trong class C #

Hàm tạo là bắt buộc khi định nghĩa class. Tuy nhiên chương trình dịch của C# có khả năng tự sinh hàm tạo cho class nếu nó không nhìn thấy định nghĩa hàm tạo nào trong class. Loại hàm tạo này có tên gọi là hàm tạo mặc định (default constructor). Hàm tạo mặc định không có tham số đầu vào.

Nếu trong khai báo class chúng ta tự viết một hàm tạo không có tham số đầu vào, hàm tạo này không được gọi là hàm tạo mặc định nữa mà được gọi là hàm tạo không tham số (parameter-less/zero-parameter constructor), vì nó không phải do chương trình dịch của C# sinh ra.

cach-viet-ham-tao-khi-kien-thiet-xay-dung-class-trong-c-3-mindovermetal

Trong ví dụ trên, public Book() {...} là một hàm tạo không tham số nhưng nó không phải là hàm tạo mặc định.

Một khi đã định nghĩa hàm tạo riêng trong class, C# compiler sẽ không tự sinh ra hàm tạo mặc định nữa. Nghĩa là nếu bạn muốn gọi hàm tạo không tham số, bạn phải tự viết thêm hàm tạo đó. Nếu không, quá trình dịch sẽ báo lỗi.

Chuỗi constructor trong class C #, constructor initializer

Hãy kiểm soát và điều chỉnh lại class Book như sau :

internal class Book
{
    private string _authors = "Unknown author";;
    private string _title = "A new book";
    private int _year = 2019;
    private string _publisher = "Unknown publisher";

    public Book()
    {
        _authors = "Unknown author";
        _title = "A new book";
        _publisher = "Unknown publisher";
        _year = 2019;
    }

    public Book(string author)
    {
        _authors = author;
    }

    public Book(string author, string title) : this(author)
    {
        _title = title;
    }

    public Book(string author, string title, int year): this(author, title)
    {
        _year = year;
    }

    public Book(string author, string title, int year, string publisher) : this(author, title, year)
    {            
        _publisher = publisher;
    }

    public string Print()
    {
        return $"{_authors}, \"{_title}\", -{_publisher}, {_year}";
    }
}

Những kiểm soát và điều chỉnh trên sử dụng một năng lực đặc biệt quan trọng của C # : constructor gọi lẫn nhau. Khi cho những constructor gọi lẫn nhau như trên bạn hoàn toàn có thể tạo ra một chuỗi constructor với số lượng tham số tăng dần, đồng thời tận dụng được code của constructor kiến thiết xây dựng trước đó .

Cấu trúc : this (...) như trên có tên gọi là constructor initializer, là loại cấu trúc đặc biệt cho phép gọi đến constructor khác và truyền tham số phù hợp cho nó.

Trong ví dụ trên, this(author) là lời gọi đến constructor Book(string author) trước đó; this(author, title) là lời gọi đến Book(string author, string title); v.v..

Constructor initializer luôn luôn thực thi trước constructor gọi nó. Khi tích hợp tốt những constructor initializer như trên, bạn hoàn toàn có thể tạo ra một chuỗi constructor với số lượng tham số tăng dần mà không cần viết lặp lại code của những constructor trước đó .Khi tạo chuỗi constructor như trên, bạn hoàn toàn có thể khởi tạo object với bất kể constructor nào :

var b1 = new Book(); // dùng hàm tạo không tham số
var b2 = new Book("Donald Trump"); // gọi hàm tạo Book(string author)
var b3 = new Book("Donald Trump", "C# for dummy"); // gọi hàm tạo Book(string author, string title)
var b4 = new Book("Donald Trump", "C# for dummy", 2020); // gọi hàm tạo Book(string author, string title, int year)

Lưu ý: Nếu trong class sử dụng public property thay cho biến thành viên, bạn nên khởi tạo object với property theo cú pháp object initializer (đã xem xét ở trên), và do đó không cần tạo chuỗi constructor. Object initializer là cú pháp được khuyến khích (và yêu thích) trong C# đối với các domain class.

Vấn đề khởi tạo và sử dụng object

Quan hệ class và object

Có thể tưởng tượng class giống như một bản thiết kế trên giấy của một ngôi nhà. Tự bản thân bản thiết kế này không phải ngôi nhà. Và có bản thiết kế không có nghĩa là tất cả chúng ta có ngôi nhà .Chỉ khi bạn sử dụng bản thiết kế này để thiết kế xây dựng được một / một số ít ngôi nhà đơn cử, bản thiết kế đó mới có giá trị .

Quá trình sử dụng bản thiết kế để xây dựng ngôi nhà có thể xem như tương đương với quá trình khởi tạo đối tượng (object initialization/instantiation) trong C#. Sau khi có ngôi nhà, chúng ta mới có thể ở. Quá trình sử dụng ngôi nhà này tương đương với việc sử dụng object để giải quyết các vấn đề của chương trình.

Trong lập trình hướng đối tượng người tiêu dùng hoàn toàn có thể phân biệt ba quá trình :

  1. Xây dựng class: định nghĩa kiểu dữ liệu, tương tự như tạo bản thiết kế ngôi nhà;
  2. Khởi tạo object: khai báo và gán giá trị đầu cho biến, tương tự giai đoạn xây nhà theo thiết kế;
  3. Sử dụng object: sử dụng biến trong các lệnh và biểu thức, tương tự khai thác ngôi nhà.

Khai báo và khởi tạo object

Việc khai báo một object triển khai tựa như như khai báo biến thuộc những kiểu tài liệu cơ sở mà bạn đã biết. Tuy nhiên, việc khai báo đơn thuần như vậy không đủ để sử dụng object, vì khi đó C # đơn thuần gán cho object giá trị null – giá trị mặc định của object, mà không thực sự cấp phép bộ nhớ cho object .

Việc truy xuất một object có giá trị null luôn luôn gây lỗi NullReferenceException ("Object reference not set to an instance of an object."). Ngoài ra, trình biên dịch của C# luôn bắt buộc các biến cục bộ phải được khởi tạo (instantiation, initialization) trước khi sử dụng.

Khi khởi tạo, một object sẽ được tạo ra trong vùng nhớ heap. Nếu tác dụng khởi tạo gán cho một biến, địa chỉ của object sẽ được gán cho biến này. Bản thân địa chỉ của object chỉ là một số lượng. Con số này lại được lưu trong stack của phương pháp .Do khởi tạo object thực ra là lời gọi tới hàm tạo, C # bắt buộc mỗi class phải có hàm tạo .

Truy xuất những thành viên của object

Trong định nghĩa class, tất cả chúng ta đã biết ba loại thành viên là biến thành viên, đặc tính, và phương pháp. Khi một object được khai báo và khởi tạo, tất cả chúng ta hoàn toàn có thể sử dụng những thành viên này để thực sự chứa dữ liệu hoặc giải quyết và xử lý tài liệu .Việc truy xuất những thành viên chỉ hoàn toàn có thể triển khai trải qua tên object, không hề thực thi qua tên class ( trừ thành viên static sẽ học sau )

Để phân biệt, người ta sử dụng thuật ngữ instance members ( gồm có instance method, instance variable, instance property ) để miêu tả những thành viên của class mà chỉ thực sự sống sót sau khi khởi tạo object. Sự sống sót của những thành viên này phụ thuộc vào vào object ( vốn cũng được gọi là một instance của class ) .Để truy xuất thành viên của object tất cả chúng ta sử dụng phép toán “. ” với tên object.

Truy xuất phương pháp thành viên đơn thuần là một lời gọi phương pháp từ một object nào đó. Việc truy xuất phương pháp thành viên cũng sử dụng cấu trúc tựa như :Có sự độc lạ khi truy xuất thành viên của một object từ client code với việc truy xuất trong nội bộ một class

Client code là đoạn code nơi triển khai khởi tạo và sử dụng object .Nếu trong định nghĩa class, một thành viên được xác lập là protected hoặc private sẽ không hề truy xuất được từ client code mà chỉ hoàn toàn có thể được truy xuất trong nội bộ class .Chỉ những thành viên được xác lập là public mới hoàn toàn có thể được truy xuất từ client code .

Khi truy xuất thành viên từ trong nội bộ của class thì không cần sử dụng phép toán truy xuất thành viên. Tuy nhiên có một số tình huống đặc thù sẽ phải sử dụng đến từ khóa this và phép toán truy xuất thành viên.

Từ khóa this

Giả sử trong constructor bạn đặt tên cho tham số như sau :

    public Book(string _authors)
    {
        _authors = _authors; // làm sao phân biệt _authors nào là member class, _authors nào là tham số???
    }

Tham số _authors giờ trùng tên với biến thành viên _authors. Cách đặt tên này không vi phạm gì trong C #. Vấn đề giờ đây là, làm thế nào để phân biệt _authors nào là thành viên class, _authors nào là tham số ? ? ?

Trong những tình huống thế này, bạn có thể sử dụng từ khóa this để chỉ rõ đâu là thành viên của class:

  this._authors = _authors;

Từ khóa this cho phép chỉ định chính bản thân object nơi đang thực thi code. Trong ví dụ trên, this._authors báo hiệu rằng cần dùng chính biến thành viên _authors của object đó. Điều này cũng có nghĩa là bạn có thể dùng this trước mọi thành viên của class. Tuy nhiên, bạn nên hạn chế sử dụng this nếu có thể vì nó làm code nhìn phức tạp hơn.

Từ khóa this cũng có một tính năng phụ khác khá tốt. Nếu bạn không nhớ hết những thành viên của class, bạn hoàn toàn có thể gõ this, dấu chấm, và chờ intellisense giúp liệt kê hết những thành viên ( non-static ) của class đó .Từ khóa this giúp liệt kê thành viên của class

Từ khóa this chỉ có tác dụng với các thành viên bình thường (không có từ khóa static).

Kết luận

Bài học này đã phân phối rất đầy đủ cho bạn những thông tin về constructor trong C # cũng như cách khởi tạo và sử dụng object .

+ Nếu bạn thấy site hữu ích, trước khi rời đi hãy giúp đỡ site bằng một hành động nhỏ để site có thể phát triển và phục vụ bạn tốt hơn.
+ Nếu bạn thấy bài viết hữu ích, hãy giúp chia sẻ tới mọi người.
+ Nếu có thắc mắc hoặc cần trao đổi thêm, mời bạn viết trong phần thảo luận cuối trang.
Cảm ơn bạn!

5/5 - (1 vote)

Bài viết liên quan

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments