- Khai báo phương thức
- Gọi phương thức
- Tham số trong phương thức
- Tham số có giá trị mặc định
- Truyền tham số với tên
- Tham chiếu và tham trị
- Đệ quy
Khai báo phương thức trong C#
Phương thức (method
, gần giống function
hàm trong lập trình hướng thủ tục)
trong C# là một nhóm các lệnh nhằm thực hiện một tác vụ nào đó,
dùng phương thức để sử dụng lại code,
dễ dàng kiểm tra và bảo trì ứng dụng. Phương thức có thể thuộc về một đối tượng lớp nào đó, hoặc không
tuy nhiên khai báo phương thức thì phải khai báo trong một lớp nào đó.
Lớp là một cách tổ chức code của lập trình hướng đối tượng - ta sẽ tìm kiểu kỹ về lớp ở các phần sau.
Xem lại chương trình C# đầu tiên ở phần 1, bạn thấy có một hàm Main
được khai báo bên trong
thân của lớp tên là Program
, hàm này mặc dù khai báo trong lớp Program
nhưng có
từ khóa static
ở phía trước, nên nó có thể chạy mà không cần phải tạo đối tượng từ lớp Program
Cú pháp khai báo một phương thức cơ bản như sau:
<Access Modifiers> <return type> <name_method>(<parameters>) { // Các câu lệnh trong phương thức }
-
Access Modifiers
cho biết cấp độ được phép truy cập đến hàm này (nói kỹ thi học về hướng đối tượng), có các mức độ nhưpublic
,private
,protect
,internal
... Nếu thiếu thành phần này thì mặc định coi làinternal
(truy cập được ở các file cùngassembly
cùng file code). Ngoài ra đếu cho vào từ khóastatic
ở trướcAccess Modifiers
thì phương thức (hàm) đó gọi là PHƯƠNG THỨC TĨNH (Truy cập được mà không cần tạo đối tượng lớp), thường dùng kèm với Access Modify tênpublic
để tạo các hàm chức năng, tiện ích. return type
là kiểu trả về của hàm nhưint, double, string ...
nếu hàm không có kiểu trả về thì đề từ khóavoid
.name_method
tên của phương thức do bạn đặt.parameters
là các tham số của hàm nếu có, các tham số khai báo theo mẫukiểu tên
nhưint thamso1
, nhiều tham số thì cách nhau bởi dấu,
.- Cuối cùng là phần thân hàm
{ }
, trong đó chứa các câu lệnh C# mà khi hàm được gọi nó sẽ thi hành theo logic của code từ đấu đến cuối, hoặc khi gặp lệnhreturn;
. Khi hàm có kiểu trả về thì trong thân hàm bắt buộc phải có câu lệnhreturn value;
(vớivalue
là giá trị, đối tượng, biểu thức có kiểu cùng kiểu tra về của hàm)
Ví dụ 1) Khai báo hàm (phương thức) tĩnh có tên BinhPhuong
trong lớp Program
, phương thức có một tham số kiểu double, trả về kiểu double là bình phương của
tham số. Sau đó gọi hàm tính bình phương của 5.
using System; namespace CS06_Method { class Program { /// Tính bình phương của số thực double static double BinhPhuong(double number) { double ketqua = number * number; return ketqua; } static void Main(string[] args) { double bp = BinhPhuong(5); // Gọi hàm Console.WriteLine("Bình phương của 5 là: " + bp); } } }
Chạy chương trình sẽ in ra:
Bình phương của 5 là: 25
Nhìn vào phần khai báo phương thức BinhPhuong
, thấy không chỉ rõ Access Modify
nào,
điều này có nghĩa hàm có Access Modify mặc định là internal
nghĩa là viết đầy đủ thì sẽ là:
static internal double BinhPhuong(double number)
Do có từ khóa static
nó trở thành phương thức tĩnh,
nên có thể gọi nó mà không cần tạo đối
tượng kiểu lớp Program
, để gọi hàm dạng này chỉ cần chỉ ra chính xác tên hàm.
Gọi phương thức trong C#
Để gọi, thi hành phương thức ta chỉ việc viết tên đầy đủ của phương thức và truyền vào tham số như ở khai báo.
Ta xem làm sao chỉ đích danh hàm khi gọi: bạn chỉ ra tên đầy đủ như saunamespace.class.method
Vậy để gọi được hàm BinhPhuong
trên cần viết CS006_Method.Program.BinhPhuong(5);
tham số truyền cho hàm là 5
Trong hàm Main trên, khi gọi BinhPhuong không cần viết đầy đủ mà chỉ cần BinhPhuong(5);
chúng cùng namespace nên có thể bỏ namespace, chúng cùng class nên có thể bỏ class. Hoặc đã khai báo
sử dụng thư viện với từ khóa using
ở đầu file, ví dụ using CS006_Method;
Tham số trong phương thức
Phương thức có thể khai báo không tham số, một hoặc nhiều tham số. Ví dụ phương thức sau không có tham số.
Tạo file CS006.cs
, trong đó khai báo một lớp tên CS006
có phương thức
XinChao
using System; // Khai báo namespace mới tên MyLib namespace MyLib { // Khai báo lớp tên CS006 public class CS006 { // Khai báo phương thức trong lớp public static void XinChao() { Console.WriteLine("Xin chào C# \n"); } } }
Quay trở lại phương thức Main trong Program.cs
, gọi nó 3 lần, kết quả có 3 dòng thông báo hiện thị.
Do gọi từ namespace khác nên đầu file Program.cs
cần thêm vào
using MyLib;
Khi gọi chỉ rõ tên lớp:
CS006.XinChao(); CS006.XinChao(); CS006.XinChao();
Phương thức có thể khai báo có một hoặc nhiều tham số, mỗi tham số khai bảo chỉ ra kiểu int, float ...
và tên của tham số, nếu có nhiều tham số thì cách nhau bởi dấu ,
Ví dụ, phương thức SoLon có hai tham số là số nguyên, trả về là số lớn hơn.
using System; namespace MyLib { public class CS006 { // Khai báo hàm có 2 tham số kiểu int, trả trà số kiểu in public static int SoLon(int num1, int num2) { int max = (num1 > num2) ? num1 : num2; return max; } } }
Trong Main gọi thử hàm này, với tham số truyền vào hàm viết đúng thứ tự
var max = CS006.SoLon(12, 40); // gọi hàm với tham số phù hợp num1 = 12, num2 = 40 Console.WriteLine(max); // Kết quả: 40
Tham số có giá trị mặc định
Nếu muốn gọi phương thức có các tham số, mà mong muốn tham số đó sẽ nhận giá trị mặc định khi không được truyền
giá trị thì khi khai báo tham số khởi tạo ngay cho nó một giá trị mặc định bằng phép gán =
Ví dụ, hàm tính thể tích hình hộp
// Phương thức khai báo có 3 tham số, hai tham số cuối mặc định // Nếu gọi hàm không có chỉ ra tham số cuỗi thì nó lấy giá trị mặc định này public static double TheTich(double cao, double dai = 1, double rong = 1) { return cao * dai * rong; }
Phương thức này có hai tham số nhận giá trị mặc định, bạn có thể gọi phương thức:
double thetich; thetich = CS006.TheTich(2); // ~ CS006.TheTich(2,1,1) Console.WriteLine(thetich); // 2 thetich = CS006.TheTich(2,10); // ~ CS006.TheTich(2,10,1) Console.WriteLine(thetich); // 20 thetich = CS006.TheTich(1,2,3); Console.WriteLine(thetich); // 6
Truyền tham số với tên
Khi gọi phương thức như các ví dụ trên, bạn truyền các tham số bằng cách điền giá trị tham số sau tên phương thức - các tham số viết đúng thứ tự khi khi nó được khai báo.
Trong C#
nó còn có cơ chế truyền tham số bằng cách chỉ tên và giá trị khi gọi theo cấu
trúc tên:giá-trị
nếu có nhiều tham số thì cấu trúc cách nhau bởi ,
,
điều này giúp cho việc không phải viết đúng thứ tự như khai báo, có tên khi gọi nên có vẻ dễ đọc hơn.
Thử ví dụ sau:
public static string FullName(string ho, string ten, string tendem ="") { return ho + (tendem != "" ? " " + tendem :"") + " " + ten; }
Có thể gọi như cách thông thường
string fullname; fullname = CS06.FullName("Nguyễn", "A"); Console.WriteLine(fullname); //Nguyễn A fullname = CS06.FullName("ĐINH", "NAM", "HOÀNG"); Console.WriteLine(fullname); //ĐINH HOÀNG NAM
Tuy nhiên, giải phóng việc phải viết tham số theo thứ tự, bạn có thể viết:
fullname = CS06.FullName(ten: "A", ho: "Nguyễn"); // Nguyễn A fullname = CS06.FullName(tendem: "VĂN", ten: "B", ho: "PHẠM"); // PHẠM VĂN B fullname = CS06.FullName(tendem: "VĂN",ho: "PHẠM", ten: "B"); // PHẠM VĂN B fullname = CS06.FullName(ho: "PHẠM", tendem: "VĂN", ten: "B"); // PHẠM VĂN B
Truyền tham số tham chiếu và tham trị C#
Có hai hình thức truyền tham số cho phương thức khi nó được gọi là tham trị và tham chiếu
- tham trị là cách thức mặc định, ta đã sử dụng ở phần trên. Có nghĩa là gán tham số bằng một biến, thì giá trị của biến được copy và sử dụng trong phương thức như biến cục bộ, còn bản thân biến bên ngoài không hề ảnh hưởng.
- tham chiếu thì bản thân biến ở tham số sẽ được hàm sử dụng trực tiếp
(tham chiếu) chứ không tạo ra một biến cục bộ trong hàm, nên nó có tác động trực tiếp đến biến này bên ngoài.
Để sử dụng được
tham chiếu
thì khai báo tham số ở phương thức, cũng như khi gọi cần cho thêm từ khóaref
Tham số là các đối tượng lớp, mặc định là tham chiếu.
Khai báo ref
ở tham số phương thức, bắt buộc khi gọi phải sử dụng
biến làm tham số chứ không được dùng giá trị.
Ví dụ tham trị:
public static void ThamChieuThamTri(int x) { x = x * x; Console.WriteLine(x); }
Khi sử dụng:
int a = 2; ThamChieuThamTri(a); Console.WriteLine(a); // In ra // 4 // 2
Ta thấy, biến a
bên ngoài phương thức được dùng làm tham số cho phương thức,
thì giá trị của a được sao chép và gán vào biến cục bộ x
của phương thức, biến x
được biến đối nhưng biến a
bên ngoài không ảnh hưởng.
Ví dụ tham chiếu:
Sửa lại phương thức trên như sau
public static void ThamChieuThamTri(ref int x) { x = x * x; Console.WriteLine(x); }
Khi sử dụng:
int a = 2; ThamChieuThamTri(ref a); Console.WriteLine(a); // In ra // 4 // 4
Ta thấy a
sử dụng làm tham số cho phương thức, tham số x
tham chiếu đến a
, và khi trong hàm thay đổi x, nghĩa là thay đổi a
bên ngoài. (đều in ra 4)
Ngoài ra nếu gọi ThamChieuThamTri(5);
thì sẽ lỗi, vì tham chiếu yêu cầu đối số này phải là biến.
Tham chiếu với out
Ngoài dùng từ khóa ref
trong khai báo tham chiếu, bạn cũng có thể thay thế nó bằng
từ khóa out
, điểm khác biệt duy nhất là nếu dùng từ khóa out
thì tham số không
cần khởi tạo khi truyền cho phương thức, còn dùng ref
thì biến làm tham số phải khởi tạo.
public static void OutExample(out int x) { x = 100; }
Khi sử dụng:
int a; // biến a chưa khởi tạo OutExample(out a); // Giờ a = 100;
Phương thức Đệ quy
Đệ quy là phương thức khai báo, trong thân của nó có gọi lại chính nó. Ví dụ cổ điển ứng dụng đệ quy là
tính giai thừa của một số ví dụ 5! = 5.4.3.2.1
public static int giaithua(int a) { if (a == 1) return 1; // Kết thúc đệ quy return a * giaithua (a - 1); // Đệ quy }
Console.WriteLine(giaithua(5)); //120
Đệ quy khá giống vòng lặp, bạn cần có điều kiện dừng để tránh đệ quy vô tận.
Hầu hết phương thức đệ quy có thể chuyển qua sử dụng các vòng lặp, nên cũng lưu ý nếu vòng lặp đơn giản thì nên dùng lặp.
Trong nhiều ví dụ test về hiệu năng - thì đệ quy chậm hơn việc sử dụng lặp nhiều. tham khảo
Source code: CS006_Method (Git), hoặc tải ex006