Cú hai loại phương thức khởi tạo: phương thức khởi tạo đối tượng (instance constructor) và phương thức khởi tạo tĩnh (static constructor).
3.2.4.1. Phương thức khởi tạo đối tượng
Cú những thao tỏc cần thực hiện mỗi khi đối tượng được tạo
như khởi tạo giỏ trị cho cỏc biến đối tượng. Cỏc cụng việc này cú thể
làm tự động bằng cỏch dựng phương thức khởi tạo đối tượng.
Phương thức khởi tạo cú cựng tờn với lớp mà nú thuộc về, chỉ được tự động gọi bởi toỏn tử new khi đối tượng thuộc lớp được tạo..
Phương thức khởi tạo luụn khụng cú giỏ trị trả về, khi định nghĩa
phương thức khụng cần ghi void.
Khi bạn khụng định nghĩa tường minh phương thức khởi tạo cho một lớp, C# sẽ tạo phương thức khởi tạo mặc nhiờn cho lớp đú.
Phương thức khởi tạo mặc nhiờn khụng cú danh sỏch tham đối, tự động gỏn tất cả cỏc biến của đối tượng về trị rỗng theo quy ước mặc
định của C#, trị 0 cho kiểu số, ký tự ‘\0’ cho kiểu ký tự char, trị false cho kiểu bool, trị null cho cỏc đối tượng.
Vớ dụ: using System; class NhanVien { string HoTen; int NamSinh; float HeSoLuong;
public static int LuongCB; public NhanVien() {}
public NhanVien(string ht, int ns, float hsl) {
HoTen = ht; NamSinh = ns; HeSoLuong = hsl;
}
public string GetHoTen() {
return HoTen; }
public float Luong() {
return LuongCB * HeSoLuong; }
}
class Test {
public static void Main(string[] args) {
NhanVien.LuongCB=290;
NhanVien nv1 = new NhanVien();
Console.WriteLine("Luong cua nhan vien {0} la {1}", nv1.GetHoTen(), nv1.Luong());
NhanVien nv2 = new NhanVien("Nguyen A", 1977, 3.0F); Console.WriteLine("Luong cua nhan vien {0} la {1}",
nv2.GetHoTen(), nv2.Luong()); }
}
Khởi tạo đối tượng và danh sỏch (Object and collection
initializer): C# 3.0 cũng cung cấp đặc tớnh khởi tạo đối tượng và danh sỏch (object and collection initializer) cho phộp khởi tạo cỏc đối tượng và danh sỏch khụng cần phải cú phương thức khởi tạo.
class NhanVien {
string hoTen; int namSinh; public string HoTen {
get { return hoTen; } set { hoTen = value; } }
public int NamSinh {
get { return namSinh; } set { namSinh = value; }
} }
class Test {
static void Main(string[] args) {
NhanVien v = new NhanVien { HoTen = "Lan", NamSinh = 1983 }; List<NhanVien> list = new List<NhanVien>
{
new NhanVien{HoTen = "Lan", NamSinh = 1980}, new NhanVien{HoTen = "Hoa", NamSinh = 1982} };
Console.WriteLine(list.Count.ToString()); }
}
3.2.4.2. Phương thức khởi tạo tĩnh (Static constructor)
Phương thức khởi tạo tĩnh sẽ được thực hiện trước khi bất kỳ
thể hiện nào của lớp được tạo, thường dựng để khởi tạo giỏ trị cho cỏc
biến tĩnh. Phương thức khởi tạo tĩnh hữu dụng khi chỳng ta cần cài
đặt một số cụng việc mà khụng thể thực hiện khi khởi tạo đối tượng,
và chỉ được thực hiện duy nhất một lần. Phương thức khởi tạo tĩnh
khụng cú tham đối, khụng cú điều khiển truy cập và khụng được gọi tường minh mà sẽ được gọi tự động.
Vớ dụ: Bổ sung phương thức khởi tạo tĩnh cho lớp NhanVien như sau: class NhanVien { string HoTen; int NamSinh; float HeSoLuong;
private static int LuongCB; static NhanVien()
LuongCB = 290; }
}
Thay vỡ sử dụng phương thức khởi tạo tĩnh để khởi tạo biến
tĩnh, ta cú thể khởi tạo biến tĩnh như sau:
private static int LuongCB = 290; hay
public static int LuongCB; và khởi tạo biến tĩnh bất kỳ đõu:
NhanVien.LuongCB = 290;
3.2.5. Phương thức hủy (Destructor)
Mỗi lớp chỉ cú một phương thức hủy để hủy một đối tượng của
nú. Phương thức hủy chỉ được gọi tự động khi một đối tượng khụng cũn được truy cập nữa, thụng qua bộ thu gom rỏc tự động (garbage collection).
Phương thức hủy cũng cú tờn trựng tờn lớp, nhưng khụng cú
tham đối, khụng cú điều khiển truy cập và được bắt đầu bằng dấu ~. Cỏc đối tượng cấp phỏt động bằng toỏn tử new, khi khụng tồn
tại biến nào trỏ đến đối tượng, đối tượng đú xem như khụng cũn cần
đến nữa và bộ nhớ dành cho nú cú thể được tự động giải phúng bởi bộ
thu gom rỏc. Trỡnh thu gom rỏc hoạt động trong một tuyến đoạn (thread) độc lập với chương trỡnh của bạn. Bạn khụng phải bận tõm gỡ với cụng việc này. Tuy nhiờn, khi làm việc với cỏc đoạn mó khụng
được quản lý thỡ cần phải khai bỏo tường minh phương thức hủy để
giải phúng tài nguyờn.
Vớ dụ: class Library {
private int ibooktypes; public Library()
{
ibooktypes = 5; }
public Library(int value) { ibooktypes = value; } ~ Library() { //thực thi cõu lệnh } } 3.2.6. Từ khoỏ this
Từ khoỏ this dựng để chỉ đến đối tượng của lớp hiện hành. Bỡnh
thường, khi cỏc phương thức truy xuất biến thành viờn hay phương
thức ngay trong lớp của nú, chỉ cần ghi tờn của biến thành viờn hay
phương thức mà khụng cần chỉ rừ tờn đối tượng hay lớp, C# ngầm
hiểu là biến hay phương thức của đối tượng hiện hành.
Tuy nhiờn sử dụng từ khoỏ this để truy xuất phương thức hay
biến thành viờn ngay trong lớp của nú là cần thiết trong một số trường
hợp, hay làm cho chương trỡnh rừ ràng, dễ đọc hơn
this.BiếnThànhViờn
this.PhươngThức(DanhSỏchTham Đối)
Chẳng hạn như khi biến cục bộ hay tham đối truyền cho phương
thức được đặt tờn trựng với biến thành viờn của lớp, nú sẽ che khuất biến thành viờn trong thõn phương thức, khi đú ta sử dụng từ khoỏ this để truy xuất biến thành viờn.
Khụng sử dụng từ khúa this để truy xuất thành viờn static của lớp.
Vớ dụ: using System; class ViDu {
int a;
public void HienThi() { int a = 5; Console.WriteLine(a); } public ViDu(int a) { this.a = a; }
public static void Main(string[] args) {
ViDu v = new ViDu(2); v.HienThi(); } } Vớ dụ: using System; namespace NhanVien { class NhanVien { string HoTen; int NamSinh; float HeSoLuong;
public static int LuongCB;
public NhanVien(string HoTen, int NamSinh, float HeSoLuong) {
this.HoTen = HoTen; this.NamSinh = NamSinh; this.HeSoLuong = HeSoLuong; }
public float Luong() {
} }
class DSNhanVien {
NhanVien[] m = new NhanVien[100]; int n = 0;
//Thờm nhõn viờn vào cuối mảng
public void Them(NhanVien v) {
m[n] = v; n++; }
// Tớnh tổng lương nhõn viờn
public float Tong() {
float TongLuong=0 ; for (int i = 0; i <n; i++)
TongLuong += m[i].Luong(); return TongLuong; } } class Test {
public static void Main(string[] args) {
DSNhanVien ds = new DSNhanVien(); NhanVien.LuongCB=290;
NhanVien nv1 = new NhanVien("Nguyen A", 1975, 1.96F); ds.Them(nv1);
NhanVien nv2 = new NhanVien("Nguyen B", 1977, 3.0F); ds.Them(nv2);
Console.WriteLine("Tong luong la: "+ds.Tong()); }
} }
3.2.7. Nạp chồng phương thức (Overloading method)
C# cho phộp bạn định nghĩa nhiều phương thức trựng tờn trong cựng một lớp, nhưng khỏc nhau về số lượng hoặc kiểu tham đối truyền cho phương thức, C# xem đõy là cỏc phương thức khỏc nhau.
Khả năng như vậy gọi là nạp chồng phương thức.
Phương thức khởi tạo cũng cú thể được nạp chồng như phương
thức bỡnh thường nghĩa là ta được phộp định nghĩa nhiều phương thức
khởi tạo khỏc nhau về số lượng hay kiểu tham đối.
Vớ dụ: using System; class NhanVien { string HoTen; int NamSinh; float HeSoLuong;
public static int LuongCB; public NhanVien() { }
public NhanVien(string HoTen, int NamSinh, float HeSoLuong) {
this.HoTen = HoTen; this.NamSinh = NamSinh; this.HeSoLuong = HeSoLuong;
}
public float Luong() {
return LuongCB * HeSoLuong; }
public string GetHoTen() {
return HoTen; }
public static void Main(string[] args) {
NhanVien nv1 = new NhanVien();
Console.WriteLine("Luong cua {0} la {1}", nv1.GetHoTen(), nv1.Luong());
NhanVien nv2 = new NhanVien("Nguyen Thi Hoa",1980,1.96F); Console.WriteLine("Luong cua {0} la {1}", nv2.GetHoTen(),
nv2.Luong()); }
}
3.2.8. Truyền tham đối cho phương thức
C# cung cấp ba cỏch truyền tham đối cho phương thức: truyền bằng giỏ trị (value), truyền bằng tham chiếu (reference) và truyền kết quả (output).
Truyền bằng tham chiếu: truyền tham chiếu, khụng phải
truyền giỏ trị của tham đối thực sự cho tham đối hỡnh thức, mà sẽ thực hiện trờn chớnh đối tượng truyền vào, vỡ vậy thay đổi với tham đối hỡnh thức sẽ tỏc động đến tham đối thực sự,
nghĩa là tham đối thực sự sẽ chịu ảnh hưởng bởi sự thay đổi
của phương thức. Tham đối này gọi là tham biến. Tham đối cú kiểu tham chiếu sẽ được truyền tham chiếu vào
phương thức.
Truyền bằng giỏ trị: tạo bản sao của cỏc tham đối truyền vào
phương thức, nghĩa là sao chộp giỏ trị của tham đối thực sự cho tham đối hỡnh thức. Vỡ vậy thay đổi trờn tham đối hỡnh thức khụng tỏc động đến tham đối thực sự, nghĩa là tham đối
hỡnh thức khụng thay đổi trước và sau khi truyền cho phương
thức. Tham đối này gọi là tham trị. Tham đối cú kiểu giỏ trị
sẽ được truyền giỏ trị vào cho phương thức.
Vớ dụ:Truyền tham đối dưới dạng tham trị cho phương thức
using System; class Program {
{ num = 5; } } class Test {
static void Main(string[] args) {
int val = 2;
Program p = new Program(); p.Change(val);
Console.WriteLine("Gia tri cua val sau khi goi phuong thuc la {0}", val);
} }
Chỳ ý với kiểu string là kiểu tham chiếu nhưng truyền bởi giỏ
trị, bởi vỡ cỏc thao tỏc trờn string thật sự tạo ra một đối tượng mới,
chỳng ta thực hiện trờn bản sao để tham chiếu đến đối tượng mới, nhưng thật sự chuỗi gốc khụng thay đổi.
Vớ dụ: using System; class Program {
static void HoanVi(string s1, string s2) {
string temp = s1; s1 = s2;
s2 = temp;
Console.WriteLine("Trong phương thuc: {0} {1}", s1, s2);
}
static void Main(string[] args) {
string str1 = "Hello"; string str2 = "World";
HoanVi(str1, str2);
Console.WriteLine("Sau khi hoan vi: {0} {1}", str1, str2); }
}
Sử dụng từ khúa refđể truyền tham chiếu: C# cũn cung cấp khả
năng cho phộp ta truyền cỏc tham đối cú kiểu giỏ trị dưới hỡnh thức là tham chiếu, bằng cỏch bổ sung từ khúa ref.
Vớ dụ:Truyền tham đối dưới dạng tham chiếu cho phương thức.
using System; class Program {
public void Change(ref int num) { num = 5; } } class Test {
static void Main(string[] args) {
int val = 2;
Program p = new Program(); p.Change(ref val);
Console.WriteLine("Gia tri cua val sau khi goi phuong thuc la {0}", val);
} }
Để kiểu tham chiếu string cú thể truyền bằng tham chiếu, sử
dụng từ khúa ref như sau:
Vớ dụ: using System; class Program {
{
string temp = s1; s1 = s2;
s2 = temp;
Console.WriteLine("Trong phương thuc: {0} {1}", s1, s2);
}
static void Main(string[] args) {
string str1 = "Hello"; string str2 = "World";
Console.WriteLine("Truoc khi hoan vi: {0} {1}", str1, str2); HoanVi(ref str1, ref str2);
Console.WriteLine("Sau khi hoan vi: {0} {1}", str1, str2); }
}
Cú thể sử dụng lớp StringBuilder trong namespace System.Text để truyền tham chiếu như sau:
Vớ dụ: using System; using System.Text; class Program {
static void HoanVi(StringBuilder s1, StringBuilder s2) {
StringBuilder temp = new StringBuilder(); temp.Append(s1);
s1.Remove(0, s1.Length); s1.Append(s2);
s2.Remove(0, s2.Length); s2.Append(temp);
Console.WriteLine("Trong phương thuc: {0} {1}", s1, s2); }
static void Main(string[] args) {
StringBuilder str2 = new StringBuilder("World");
Console.WriteLine("Truoc khi hoan vi: {0} {1}", str1, str2); HoanVi(str1, str2);
Console.WriteLine("Sau khi hoan vi: {0} {1}", str1, str2); }
}
Sử dụng từ khúa out để truyền tham chiếu kết quả (output): Ngụn ngữ C# bắt buộc phải thực hiện một phộp gỏn cho biến trước
khi sử dụng, do đú khi khai bỏo một biến cục bộ thỡ trước khi sử dụng
cỏc biến này, phải gỏn giỏ trị cho biến. Vỡ vậy, nếu bạn muốn truyền tham đối kiểu giỏ trị dưới dạng tham chiếu khi gọi phương thức, nhưng khụng cần phải khởi tạo giỏ trị cho tham đối, mà chỉ muốn
nhận giỏ trị của tham đối, phải sử dụng từ khúa out.
Vớ dụ:Truyền tham đối dưới dạng kết quả cho phương thức
using System;
namespace TruyenThamDoi {
class Program {
public static void Sum(int num1, int num2, out int result) {
result = num1 + num2; }
}
class Test {
static void Main(string[] args) {
int val1 = 2, val2 = 5; int output;
Program.Sum(val1, val2, out output); Console.WriteLine("Tong la {0}", output); }
} }
3.2.9. Nạp chồng toỏn tử (Overloading operator)
Phương thức nạp chồng toỏn tử là một thành viờn của lớp, để định nghĩa một phộp toỏn sử dụng cho đối tượng của lớp. Cú ba kiểu
phộp toỏn cú thể nạp chồng: một ngụi (unary operator), hai ngụi
(binary operator) và phộp chuyển kiểu. Cỳ phỏp phương thức nạp
chồng ba kiểu phộp toỏn này như sau:
BổTừ Kiểu Operator PhộpToỏnMộtNgụi(ThamĐối){ //Thõn phương thức
}
BổTừ Kiểu Operator PhộpToỏnHaiNgụi(Tham Đối1, ThamĐối2){
//Thõn phương thức
}
BổTừ implicit/ explicitOperator
KiểuChuyểnĐổi(ThamĐối){
//Thõn phương thức
}
Trong đú:
Bổ từ (Modifier) là cỏc từ khúa public, static hay extern.
Từ khoỏ extern chỉ ra rằng phương thức được gọi tồn tại trong một thư viện DLL
Một phương thức nạp chồng toỏn tử phải là một phương thức
tĩnh static
Kiểu (Data type) là kiểu dữ liệu trả về của phộp toỏn
Phộp toỏn một ngụi là phộp toỏn cú một toỏn hạng như + - ! ~ ++ --
Phộp toỏn hai ngụi là phộp toỏn cú hai toỏn hạng như + - * / % & | ^ << >> == != > < >= <=
Khi nạp chồng phộp toỏn so sỏnh, phải nạp chồng cho phộp toỏn trỏi ngược của nú, vớ dụ nạp chồng phộp so sỏnh ==, ta
phải nạp chồng cả phộp so sỏnh !=, nếu khụng chương trỡnh sẽ bỏo lỗi.
Kiểu chuyển đổi (Convert type) là kiểu dữ liệu cần chuyển đổi thành.
implicit/ explicit là từ khúa cho phộp chuyển kiểu mặc định hay tường minh.
Vớ dụ:
Chuyển kiểu mặc định phõn số a thành double: double d = a;
Chuyển kiểu tường minh phõn số a thành double: double d = (double) a;
Tham đối (Parameter) cú dạng: Kiểu ThamĐối
Thõn phương thức phải cú lệnh trả về giỏ trị cho phộp toỏn
Vớ dụ:Định nghĩa cỏc phộp toỏn cho lớp PhanSo
using System; class PhanSo {
int tu, mau; public int Tu { get { return tu; } }
public int Mau {
get {
return mau; }
public PhanSo(int tu, int mau) { this.tu = tu; this.mau = mau; } // Nạp chồng phộp cộng
public static PhanSo operator+(PhanSo a, PhanSo b) {
PhanSo tong = new PhanSo(a.tu * b.mau + b.tu * a.mau, a.mau * b.mau);
return tong; }
// Nạp chồng phộp nhõn
public static PhanSo operator*(PhanSo a, PhanSo b) {
return new PhanSo(a.tu * b.tu, a.mau * b.mau); }
// Nạp chồng phộp chuyển kiểu mặc định (implicit) thành double // Hay nạp chồng phộp chuyển kiểu tường minh (explicit thay cho implicit)
public static implicit operator double(PhanSo a) {
return (double) a.tu / a.mau; }
// Nạp chồng phộp so sỏnh ==
public static bool operator==(PhanSo a,PhanSo b) { if(a.tu*b.mau == a.mau*b.tu) return true; return false; } // Nạp chồng phộp so sỏnh !=
public static bool operator==(PhanSo a,PhanSo b) {
if (a.tu*b.mau != a.mau*b.tu) return true;
} }
class Test {
public static void Main() {
PhanSo a = new PhanSo(1, 2); PhanSo b = new PhanSo(3, 7); PhanSo c = new PhanSo(2, 3);
// Chuyển kiểu mặc định
Console.WriteLine(a * b + c); // Chuyển kiểu tường minh
Console.WriteLine((double)(a * b + c)); }
}
3.3. THUỘC TÍNH (PROPERTIES)
Thuộc tớnh là một đặc tớnh mới được giới thiệu trong ngụn ngữ C#. Đặc tớnh này cung cấp khả năng bảo vệ cỏc biến dữ liệu bờn trong một lớp bằng việc đọc và ghi chỳng thụng qua thuộc tớnh. Trong ngụn
ngữ khỏc, điều này cú thể được thực hiện thụng qua việc tạo cỏc phương thức truy cập (getter method hay accesser) và phương thức
thiết lập (setter method hay mutator).
Vớ dụ: class ViDu {
int a;
public int geta () {
return this.a; }
public void seta ( int a ) {
this.a = a; }
Cú thể được viết trong C# như sau, và cú thể dễ dàng truy cập
trực tiếp property bờn trong một chương trỡnh C#. class ViDu { int a; public int A { get { return this.a; } set {
// value là biến được tạo ra bởi trỡnh biờn dịch để thay thế
tham đối this.a = value; } } } class Test {
static void Main(string[] args) {
ViDu v = new ViDu(); v.A = 3;
Console.WriteLine(v.A); }
}
Lợi ớch của việc sử dụng thuộc tớnh (property) là cho phộp cỏc thành phần bờn ngoài cú thể truy cập thuộc tớnh một cỏch trực tiếp mà vẫn đảm bảo tớnh đúng gúi trong thiết kế hướng đối tượng.
Thuộc tớnh được tự động cài đặt (Auto-implemented properties):
C# 3.0 cho phộp cỏc thuộc tớnh của lớp được tự động cài đặt (auto- implemented properties). Đa số cỏc properties đều thực hiện cỏc thao tỏc như là ghi và đọc từ 1 biến private nào đú. Trong C# 3.0, nếu như
private thỡ chỉ cần khai bỏo ngắn gọn như sau, trỡnh biờn dịch sẽ tự động tạo biến private vụ danh tương tự khai bỏo tường minh. Để một
thuộc tớnh chỉ được đọc hay ghi giỏ trị trong lớp chứa thuộc tớnh,
thờm từ khúa private trước từ khúa get hay set.
Vớ dụ:
public class ViDu {
public int A { get; set; }
//public int A { get; private set; } }
Thuộc tớnh chỉ đọc (Read only property): Giả sử chỳng ta
muốn tạo lớp Time cung cấp một số thuộc tớnh static để hiển thị ngày hiện hành.
Vớ dụ: using System;
public class RightNow {
public static int Year; public static int Month; public static int Date; static RightNow() { DateTime dt = DateTime.Now; Year = dt.Year; Month = dt.Month; Date = dt.Day; } }
public class Tester {
static void Main() {