Lập trình Windows - Chương 2: Ngôn ngữ lập trình C# (Phần 1)

pptx 141 trang vanle 1960
Bạn đang xem 20 trang mẫu của tài liệu "Lập trình Windows - Chương 2: Ngôn ngữ lập trình C# (Phần 1)", để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên

Tài liệu đính kèm:

  • pptxlap_trinh_windows_chuong_2_ngon_ngu_lap_trinh_c_phan_1.pptx

Nội dung text: Lập trình Windows - Chương 2: Ngôn ngữ lập trình C# (Phần 1)

  1. Lập trình Windows Chương 2. Ngôn ngữ lập trình C# Phần 1 1
  2. Nội dung • Tổng quan C# • Các thành phần cơ bản của ngôn ngữ • Hệ thống kiểu trong .NET • Namespace • Các câu lệnh • Lớp • Thừa kế • Property, Mảng và Indexer • Lớp Collection • Interface • Delegate và event handler • Xử lý Ngoại lệ 2 2
  3. Tổng quan C#
  4. Tổng quan C# • C# (C-Sharp) là ngôn ngữ lập trình do Microsoft sáng tạo ra dựa trên những ưu điểm của C++, Java, Smalltalk và bổ sung thêm những phần mới • Các phiên bản ngôn ngữ C# • C# 1.0 cho .NET Framework 1.0 (1.1) • C# 2.0 cho .NET Framework 2.0 (3.0) • C# 3.0 cho .NET Framework 3.5 • C# 4.0 cho .NET Framework 4.0 • C# 5.0 cho .NET Framework 4.5 • File source code C# có phần mở rộng .cs. Một chương trình gồm có một hay nhiều file source code 4
  5. Tổng quan C# • Mục tiêu thiết kế C# • Ngôn ngữ hướng thành phần (Component-orientation) • Mọi thứ đều là đối tượng • Tạo ra phần mềm mạnh và bền 5
  6. Ngôn ngữ hướng thành phần • Ngôn ngữ hướng thành phần đầu tiên trong họ C/C++ • Khái niệm hướng thành phần • Properties, methods, events • Design-time và run-time attributes • Tích hợp documentation bằng XML • Cho phép one-stop programming • Không header files, IDL, • Có thể nhúng trong các trang ASP.NET 6
  7. Mọi thứ đều là đối tượng • Quan điểm truyền thống • C++, Java™: Các kiểu cơ sở (Primitive type) không thể tương tác với các object • Smalltalk, Lisp: Các kiểu cơ sở là các object, nhưng phải trả giá về chi phí thực thi • C# thống nhất 2 loại kiểu nhưng không phải trả giá về chi phí thực thi • Tăng cường các kiểu dữ liệu khác • Các kiểu cơ sở mới : Decimal, SQL • Collections, làm việc trên tất cả các kiểu 7
  8. Tạo ra phần mềm mạnh và bền • Garbage collection (GC) • Không bị rò rỉ bộ nhớ và các con trỏ không được truy cập bất hợp lệ • Ngoại lệ (Exception) • Cho phép xử lý các ngoại lệ • An toàn kiểu (Type-safety) • Không được dùng các biến chưa khởi tạo, ép kiểu (cast) không an toàn 8
  9. Chương trình C# đầu tiên 3 using System; 2 1 class Program { static void Main(string[] args) { Console.WriteLine("Hello, World"); } } 4 9
  10. Lớp • Một ứng dụng C# gồm tập các class và struct • Một lớp gồm tập dữ liệu và phương thức • Cú pháp class ClassName { } 10
  11. Phương thức Main • Phương thức Main được định nghĩa trong lớp • Chú ý khi viết hàm Main • Ký tự M phải viết HOA, “Main” • Phải có một hàm Main là entry point của chương trình • Khai báo Main: static void Main • Khi hàm Main kết thúc hay gặp lệnh return thì ứng dụng kết thúc 11
  12. Dùng Directive và System namespace • .NET Framework cung cấp nhiều lớp tiện ích • Các lớp được tổ chức thành các namespace • System là namespace được dùng thông dụng nhất • Khi sử dụng lớp phải chỉ rõ lớp đó thuộc namespace nào System.Console.WriteLine("Hello, World"); ▪ Dùng directive using System; Console.WriteLine("Hello, World"); 12
  13. Xuất dữ liệu • Nhập dữ liệu từ bàn phím và xuất dữ liệu ra màn hình trong C# có thể dùng các phương thức tĩnh trong lớp: System.Console •Xuất dữ liệu lên màn hình • Cú pháp 1: void Console.Write(data); void Console.WriteLine(data); 13
  14. Xuất dữ liệu • Cú pháp 2: void Console.Write(string format, params object[] arg); void Console.WriteLine(string format, params object[] arg); • Trong đó: – format: chứa chuỗi định dạng – arg là mảng các đối tượng sẽ được xuất ra theo chuỗi định dạng 14
  15. Xuất dữ liệu • format là một chuỗi bình thường và có thể có thêm một hay nhiều phần định dạng có cú pháp sau • Cú pháp: {index[,alignment][:formatString]} – Trong đó: ▪ index: Số thứ tự của đối số, bắt đầu từ 0 ▪ alignment: độ rộng, M>0 canh phải, M<0 canh trái ▪ formatString: C hay c, D hay d, E hay e, F hay f 15
  16. Nhập dữ liệu • Nhập dữ liệu từ bàn phím • Cú pháp: int Console.Read(); string Console.ReadLine(); 16
  17. Nhập dữ liệu – Chuyển kiểu dữ liệu • Để chuyển một kiểu dữ liệu sang một kiểu dữ liệu khác chúng ta dùng cú pháp sau • Cú pháp Kieu.Parse(“chuoi”); ▪ Ví dụ: string s = “123”; int data = int.Parse(s); 17
  18. Nhập dữ liệu – Lớp Convert Cung cấp các phương thức static giúp chuyển đổi giữa các dữ liệu có các kiểu khác nhau Phương thức Ý nghĩa ToBoolean Chuyển một giá trị sang giá trị Boolean ToByte Chuyển một giá trị sang giá trị số nguyên 8-bit không dấu ToChar Chuyển một giá trị sang giá trị ký tự unicode ToDateTime Chuyển một giá trị sang giá trị DateTime. ToDecimal Chuyển một giá trị sang giá trị Decimal. ToDouble Chuyển một giá trị sang giá trị số thực có độ chính xác gấp đôi 8 byte ToInt16 Chuyển một giá trị sang giá trị số nguyên 16-bit có dấu ToInt32 Chuyển một giá trị sang giá trị só nguyên 32-bit có dấu ToInt64 Chuyển một giá trị sang giá trị số nguyên 64-bit có dấu ToSByte Chuyển một giá trị sang giá trị số nguyên 8-bit có dấu ToSingle Chuyển một giá trị sang giá trị số thực có độ chính xác đơn ToString Chuyển một giá trị sang giá trị một chuỗi ToUInt16 Chuyển một giá trị sang giá trị số nguyên 16-bit không dấu ToUInt32 Chuyển một giá trị sang giá trị số nguyên 32-bit không dấu ToUInt64 Chuyển một giá trị sang giá trị số nguyên 64-bit không dấu 18
  19. Các thành phần cơ bản của ngôn ngữ
  20. Từ khóa - keyword abstract as base bool break byte case catch char checked class const continue decimal default delegate do double else enum event explicit extern false finally fixed float for foreach goto if implicit in int interface internal is lock long namespace new null object operator out override params private protected public readonly ref return sbyte sealed short sizeof stackalloc static string struct switch this throw true try typeof uint ulong unchecked unsafe ushort using virtual void volatile while 20
  21. Từ khóa - keyword • Contextual Keywords add alias ascending descending dynamic from get global group into join let orderby partial (type) partial (method) remove select set value var where (generic type constraint) where (query clause) yield
  22. Định danh – Identity • Định danh – Identity: Tên lớp, tên phương thức, tên biến, tên đối tượng, tên hằng, tên kiểu, • Quy tắc tạo định danh trong C#: • Ký tự đầu tiên: chữ, ký tự gạch dưới, ký tự @ • Các ký tự còn lại: chữ, số, ký tự gạch dưới • Có thể dùng @ ở đầu từ khóa để tạo định danh 22
  23. Biến – Biến hằng • Biến - Tạo biến trong C# có một số quy tắc sau: • Biến đươc khai báo trong khối cha thì không được khai báo lại trong khối con và ngược lại. • Biến được khai báo trong vòng lặp for chỉ có tác dụng trong vòng lặp for • Biến phải được khởi tạo trước khi sử dụng • Biến hằng: const int x =555; 23
  24. Các toán tử C# Loại toán tử Toán tử Số học + - * / % Logical (boolean và bitwise) & | ^ ! ~ && || true false Nối chuỗi + Tăng, giảm ++ Dịch chuyển bit > Quan hệ == != = (3.0) Gán = += -= *= /= %= &= |= ^= >= ?? Truy cập thành viên . Chỉ mục, chỉ số [] Ép kiểu () Điều kiện ?: Nối và gở bỏ delegate += -= Tạo đối tượng new Thông tin kiểu as is sizeof typeof Điều khiển ngoại lệ tràng bộ nhớ checked unchecked Indirection và Address * -> [] & (3.0) Lambda =>
  25. Chú thích • Giống C/C++ • // • /* */ • XML Comment • /// /// /// /// 25
  26. Hệ thống kiểu .NET
  27. Common Type System – CTS • Common Type System – CTS • Mô tả các kiểu được định nghĩa như thế nào và chúng hoạt động ra sao. • CTS cung cấp các kiểu dữ liệu cơ sở mà các ngôn ngữ trên .NET Framework phải dùng. Với mục đích các chương trình được viết bằng những ngôn ngữ khác nhau dễ dàng chia sẽ thông tin với nhau 27
  28. Common Type System – CTS • Mục đích của CTS • Cho phép .NET Framework tích hợp nhiều ngôn ngữ khác nhau • Xác định các quy tắc của các kiểu mà các ngôn ngữ lập trình trên .NET phải tuân theo cho nên các đối tượng được viết bằng những ngôn ngữ khác nhau có thể tương tác với nhau 28
  29. Common Type System – CTS • Phân loại CTS • Kiểu giá trị (value type) • Kiểu giá trị chứa trực tiếp giá trị của nó và các instance của kiểu giá trị được cấp phát trên vùng stack • Kiểu tham chiếu (reference type) • Lưu tham chiếu đến vùng nhớ của giá trị (đối tượng), vùng nhớ của giá trị được cấp phát trên heap • Các biến kiểu tham chiếu chứa giá trị null để báo rằng không tham chiếu đến đối tượng nào trên vùng nhớ heap 29
  30. Common Type System – CTS 30
  31. Kiểu cơ sở trong CTS (build-in type) và Bí danh • CTS định nghĩa các kiểu cơ sở cho tất cả các ngôn ngữ lập trình trên .NET như: System.Int32, System.String, • Mỗi ngôn ngữ thường định nghĩa các bí danh cho các kiểu cơ sở trong CTS • Ví dụ: • CTS định nghĩa System.Int32 – 4 byte số nguyên • C# định nghĩa int là bí danh của System.Int32 • C# định nghĩa string là bí danh của System.String. 31
  32. Kiểu cơ sở trong CTS (build-in type) và Bí danh Bí danh trong Kiểu cơ sở C# trong CTS bool System.Boolean byte System.Byte sbyte System.SByte char System.Char Kiểu trong C# và kiểu trong System.Decimal decimal .NET Framework có thể dùng double System.Double float System.Single thay thế cho nhau int System.Int32 uint System.UInt32 long System.Int64 ulong System.UInt64 short System.Int16 ushort System.UInt16 string System.String object System.Object 32
  33. Kiểu chuỗi • Đặc điểm string • Chuỗi ký tự unicode • Kiểu tham chiếu • Kích thước cố định • Hằng chuỗi: • “” • @“” • Phép toán trên string • Toán tử ==, != dùng để so sánh các giá trị của string • +, [] 33
  34. Chuyển kiểu ngầm định • Không có chuyển kiểu ngầm định • Sang kiểu char • Giữa số thực và decimal 34
  35. Boxing và Unboxing • Vấn đề: Việc tách thành hai loại kiểu (kiểu giá trị và kiểu tham chiếu) thì làm thế nào các kiểu tương tác với nhau? • Giải pháp: Dùng 2 kỹ thuật sau đây • Boxing: là chuyển từ kiểu giá trị sang kiểu tham chiếu • Unboxing: là chuyển từ kiểu tham chiếu sang kiểu giá trị 35
  36. Boxing và Unboxing • Boxing • Ví dụ: • int a = 55; • object o = a; • Quá trình hoạt động của boxing • Trước hết một vùng nhớ được cấp phát trên vùng nhớ heap để tạo đối tượng o • Sau đó giá trị của biến kiểu giá trị được sao chép sang vùng nhớ heap đó • Cuối cùng địa chỉ của đối tượng được cấp phát trên heap được đặt vào vùng nhớ trên stack 36
  37. Boxing và Unboxing • Unboxing • Ví dụ: • int a = 55; • object o = a; • int b = (int)o; • Chú ý: • Boxing là không cần ép kiểu • Unboxing phải ép kiểu 37
  38. Boxing và Unboxing • Quá trình hoạt động của unboxing • Trước hết runtime kiểm tra xem địa chỉ trên stack có trỏ đến đối tượng hợp lệ không và kiểm tra xem kiểu đối tượng có thể được chuyển sang kiểu giá trị không. Nếu không sẽ ném ra một ngoại lệ InvalidCastException • Một con trỏ đến giá trị bên trong đối tượng được trả về. Chú ý rằng boxing tạo một bản sao của kiểu được chuyển đổi, còn unboxing thì không làm thế. 38
  39. Namespace
  40. Namespace • Được dùng để định nghĩa một phạm vi (scope). Phạm vi namespace này cho phép chúng ta tổ chức code và tạo ra các kiểu có tên duy nhất • Cú pháp: namespace { } 40
  41. Namespace • Trong namespace chúng ta có thể khai báo một hay nhiều kiểu sau đây • Namespace khác • Class • Interface • Struct • Enum • Delegate 41
  42. Namespace namespace MyProject namespace MyCompany { { class Class1 namespace Project1 { } { class Class2 class Class1 { } { } } class Class2 { } } namespace Project2 { class Class1 { } class Class2 { } } } 42
  43. Namespace • Các namespace có những đặc điểm sau • Các namespace được dùng để tổ chức các project lớn • Các namespace được cách bằng toán tử “.” • Có thể định nghĩa 1 namespace trong hai hay nhiều khai báo • Namespce “global” là namespace gốc cho các namespace (gọi là default namespace hay global namespace)global::System.Console.WriteLine(); 43
  44. Namespace namespace MyCompany namespace MyCompany.Project1 { { namespace Project1 class Class1 { { } class Class1 class Class2 { } { } class Class2 } { } namespace MyCompany.Project2 } { namespace Project2 class Class1 { { } class Class1 class Class2 { } { } class Class2 } { } } } 44
  45. Namespace namespace MyCompany.Project1 { class Class1 { } class Class2 { } } namespace MyCompany.Project1 { class Class3 { } class Class4 { } } • Chú ý: có thể có nhiều tập tin mã nguồn dùng để phân phối cho 1 namespace 45
  46. Namespace Từ khóa using • Để truy cập các thành phần bên trong namespace chúng ta dùng • Cú pháp . ▪ Để viết code dễ dàng hơn chúng ta có thể dùng câu lệnh using • Cú pháp using . ; 46
  47. Namespace Từ khóa using • Từ khóa using cho phép xác định trật tự tìm kiếm các namespace khi trình biên dich gặp một kiểu mà không có tên namespace đứng trước • Từ khóa using không dùng để xác định tên lớp using System.Console; class Program { static void Main(string[] args) { WriteLine("Hello, World"); } } 47
  48. Namespace Từ khóa using • Dùng từ khóa using để tạo bí danh cho lớp using console = System.Console; class Program { static void Main(string[] args) { console.WriteLine("Hello, World"); } } 48
  49. Các lệnh điều khiển: if, switch, goto, for, while, do while, foreach
  50. Câu lệnh if, switch • Cú pháp 1 if (expression) { Các câu lệnh } • Cú pháp 2 if (expression) { Các câu lệnh A; } else { Các câu lệnh B; } ▪ Quy tắc của câu lệnh if: Giá trị của biểu thức phải là một giá trị kiểu bool 50
  51. Câu lệnh if, switch switch (expression) { • Câu lệnh switch case const_expression1: • Cú pháp break; case const_expression2: break; case const_expressionN: break; default: break; } 51
  52. Câu lệnh if, switch • Quy tắc của câu lệnh switch: • expression phải thuộc một trong các kiểu: • số nguyên, char, string, enum • Mỗi case (kể cả default) luôn cung cấp “lệnh nhảy” (jump statement) (break, return, goto) • Nếu thân case là câu lệnh rỗng thì không cần “lệnh nhảy” • Thứ tự các case, default không quan trọng 52
  53. Câu lệnh nhảy – jump statement • Câu lệnh break, continue, return giống như trong C/C++ • Câu lệnh goto • Cú pháp goto label; goto case constExpression goto default; ▪ Quy tắc của câu lệnh nhảy: được nhảy ra, không được nhảy vào 53
  54. Câu lệnh lặp • Câu lệnh for • Cú pháp for (initialization; BooleanExpression; step) { Các câu lệnh } ▪ Câu lệnh while • Cú pháp while (BooleanExpression) { Các câu lệnh } 54
  55. Câu lệnh lặp • Câu lệnh do while • Cú pháp do { Các câu lệnh } while (BooleanExpression); 55
  56. Câu lệnh lặp • Câu lệnh foreach • Cú pháp foreach (type variableName in expression) { Các câu lệnh } • Trong đó: – type là kiểu của biến variableName – expression là đối tượng thuộc collection hay mảng 56
  57. Định nghĩa lớp • Định nghĩa lớp • Cú pháp: [attributes] [modifiers] class [:BaseClassName] { [class-body] }[;] 1 2 58
  58. Định nghĩa lớp Access modifier • Ví dụ class NhanVien { private long maNV; } ▪ Không cần thiết phải “;” để kết thúc lớp. class MyClass class MyClass { { // members // members } }; 59
  59. Thân của lớp • Một lớp trong C# có thể chứa các loại thành viên • Constants • Fields • Methods • Operators • Properties • Events • Indexers • Instance constructors, static constructors • Destructors • Các kiểu khai báo lồng nhau (class, struct, interface, enum, delegate) 60
  60. Thân của lớp Kiểu ở mức public class First cao nhất { (top-level) const int MAX = 5; string name; public int Say(string message) { return message + “ ” + name; } public class Second Kiểu bị lồng { (nested) } } 61
  61. Bổ từ truy cập Cho kiểu ở mức cao nhất • Có 2 bổ từ truy cập cho kiểu ở mức cao nhất • public public class AccessTypeInCSharp • internal { } • DEFAULT: internal class AccessInCSharp internal class AccessInCSharp { { } } 62
  62. Bổ từ truy cập Cho thành viên • Có 5 bổ từ truy cập cho thành viên • public class AccessMembersInCSharp { • protected public int a; • private public int b; public int c; protected int d; protected int e; • internal } • internal protected • DEFAULT: private 63
  63. Bổ từ truy cập Cho thành viên C++ C# class AccessMembersInCSharp { public: class AccessMembersInCSharp int a; { int b; public int a; int c; public int b; public int c; protected: protected int d; int d; protected int e; int e; } }; class AccessMembersInCSharp { protected int a; int b; } 64
  64. Bổ từ truy cập Cho thành viên • Nếu kiểu có bổ từ truy cập là internal (hay không có bổ từ truy cập) thì các thành viên của kiểu này có thể khai báo 3 cấp độ truy cập (giống C++) • public = internal = internal protected • protected • private • Nếu kiểu có bổ từ truy cập là public thì các thành viên của kiểu này có thể khai báo 5 cấp độ truy cập • public • protected • private • internal • internal protected 65
  65. Thân của lớp Field • Field • Một field là một biến thành viên dùng để lưu giữ giá trị của một đối tượng • Cú pháp: ; • Trong đó có thể là – Kiểu cơ sở: char, int, float, double, – Enum – Struct – Class – Delegate 66
  66. Thân của lớp Field • Quy tắc về khai báo Field • Field có thể là một đối tượng của lớp đang định nghĩa • Có thể vừa khai báo, vừa khởi tạo dữ liệu cho field 67
  67. Thân của lớp Phương thức • Phương thức và tham số • Trong C#, khái niệm phương thức (method) và hàm (function) là đồng nghĩa với nhau. Phương thức là đoạn mã thao tác trên các field. • Trong C#, định nghĩa phương thức theo quy tắc • Phương thức phải nằm trong class hay struct • Thân của phương thức nằm trong định nghĩa lớp (nghĩa là không có sự phân biệt giữa khai báo và định nghĩa phương thức) 68
  68. Thân của lớp Phương thức class ClassName { Method(int data) { } Tham số } hình thức class Program { static void Main() { int x = 7; ClassName obj = new ClassName(); obj.Method(x); } Tham số } thực 69
  69. Thân của lớp Phương thức • Các tham số của phương thức: có 2 loại tham số • Tham số giá trị (Value parameter – tham trị): • Khi gọi phương thức có tham số giá trị thì chúng ta đang gởi một bản sao của tham số thực cho phương thức (bất kỳ thay đổi dữ liệu của tham số trong phương thức cũng không ảnh hưởng đến dữ liệu ban đầu được lưu trong tham số thực) • Đây là cách truyền mặc định 70
  70. Thân của lớp Phương thức • Tham trị với kiểu giá trị class SomeClass { public void Change(int data) { data = data*2; } } class Program { static void Main() { SomeClass obj = new SomeClass(); int x=7; obj.Change(x); Console.WriteLine(“x=” + x); } } 71
  71. Thân của lớp Phương thức • Tham trị với kiểu tham chiếu class AnotherClass { public int data; } class SomeClass { public void Change(AnotherClass obj) { obj = new AnotherClass(); obj.data = 100; } } class Program { static void Main() { AnotherClass at = new AnotherClass() SomeClass sc = new SomeClass(); at.data = 7; sc.Change(at); Console.WriteLine(“data=” + at.data); } } 72
  72. Thân của lớp Phương thức • Tham trị với kiểu tham chiếu class AnotherClass { public int data; } class SomeClass { public void Change(AnotherClass obj) { obj.data = obj.data*2; } } class Program { static void Main() { AnotherClass at = new AnotherClass() SomeClass sc = new SomeClass(); at.data = 7; sc.Change(at); Console.WriteLine(“data=” + at.data); } } 73
  73. Thân của lớp Phương thức • Tham trị với kiểu giá trị class SomeClass { public void Change(string data) { data = “New String”; } } class Program { static void Main() { SomeClass obj = new SomeClass(); string s=“Old String”; obj.Change(s); Console.WriteLine(“s=” + s); } } 74
  74. Thân của lớp Phương thức • Tham số tham chiếu (tham chiếu): • Khi gọi phương thức có tham số tham chiếu, thì tham số thực và tham số hình thức đều chỉ đến cùng ô nhớ (bất kỳ thay đổi dữ liệu của tham số trong phương thức cũng ảnh hưởng đến dữ liệu ban đầu được lưu trong tham số thực) • Thêm modifier: ref hay out 75
  75. Thân của lớp Phương thức class ClassName { void Square1(int x) { } void Square2(ref int x) { } void Square3(out int x) } 76
  76. Thân của lớp Phương thức • Phương thức với tham số ref • Cú pháp: class ClassName { Method(ref type variableName) { } } 77
  77. Thân của lớp Phương thức • Cú pháp: sử dụng phương thức có tham số ref variableName = value; Method(ref variableName); • Chú ý – Tham số thực phải được khởi tạo trước khi gọi phương thức. – Mọi thay đổi giá trị trong tham số hình thức đều thay đổi giá trị trong tham số thực. 78
  78. Thân của lớp Phương thức • Tham chiếu với kiểu giá trị class SomeClass { public void HoanVi(ref int x, ref int y) { int tam = x; x = y; y = tam; } } class Program { static void Main() { SomeClass obj = new SomeClass(); int x=7, y=9; obj.HoanVi(ref x, ref y); Console.WriteLine(“x={0} y={1}”, x, y); } } 79
  79. Thân của lớp Phương thức • Tham chiếu với kiểu tham chiếu class SomeClass { public void HoanViChuoi(ref string s1, ref string s2) { string s = s1; s1 = s2; s2 = s; } } class Program { static void Main() { SomeClass obj = new SomeClass(); string x=“ABC”, y=“XYZ”; obj.HoanViChuoi(ref x, ref y); Console.WriteLine(“x={0} y={1}”, x, y ); } } 80
  80. Thân của lớp Phương thức • Phương thức với tham số out • Cú pháp class ClassName() { Method(out type variableName) { variableName = ; } } 81
  81. Thân của lớp Phương thức • Cú pháp: sử dụng phương thức có tham số out //variableName = value; Method(out variableName); • Chú ý – Tham số thực không nhất thiết phải được khởi tạo trước khi gọi phương thức. – Giá trị của tham số thực không được chuyển đến tham số hình thức, vì vậy không được sử dụng tham số hình thức trong phương thức nếu chưa khởi tạo. – Tham số hình thức trong phương thức phải được gán giá trị trước khi phương thức kết thúc 82
  82. Thân của lớp Phương thức class AnotherClass { public int ID; } class SomeClass { public void Change1(out AnotherClass ref1) { ref1.ID = ref1.ID * 2; } public void Change2(out AnotherClass ref1) { ref1.ID = 4; } 83
  83. Thân của lớp Phương thức public void Change3(out AnotherClass ref1) { int x = ref1.ID; ref1 = new AnotherClass(); ref1.ID = x * 2; } public void Change4(out AnotherClass ref1) { ref1 = new AnotherClass(); ref1.ID = 99; } } 84
  84. Thân của lớp Phương thức • Nhận xét: Nếu chúng ta • Chỉ muốn truyền giá trị vào cho phương thức • Tham trị • Chỉ muốn nhận 1 giá trị trả về từ phương thức • Dùng lệnh return • Chỉ muốn nhận nhiều giá trị trả về từ phương thức • Tham chiếu out • Vừa muốn truyền giá trị vào phương thức vừa cho phép thay đổi giá trị đó • Tham chiếu ref 85
  85. Thân của lớp Phương thức • Phương thức với tham số params • Tham số params cho phép chúng ta tạo ra phương thức có số lượng không xác định các tham số • Cú pháp class ClassName { Method( , params type[] variableName) { } } 86
  86. Thân của lớp Phương thức class SomeClass { public int TinhTong(params int[] arr) { int sum = 0; for (int i=0; i<arr.Length; i++) sum += arr[i]; return sum; } } class Program { static void Main() { SomeClass obj = new SomeClass(); int sum = obj.TinhTong(5,2,3); } } 87
  87. Thân của lớp Phương thức • Chú ý: – Khi dùng từ khóa params thì mảng theo sau params là tham số cuối cùng của phương thức. – Cũng có thể truyền 1 mảng cho phương thức 88
  88. Thân của lớp Method overloading • Một phương thức được xác định duy nhất bởi Chữ ký của phương thức. Chữ ký phương thức thông thường gồm: Tên phương thức, số lượng và kiểu của tham số • Trong C#, chữ ký của phương thức được xác định bởi: Tên phương thức, số lượng và kiểu của tham số • Dự trên chữ ký của phương thức, C# thực hiện chức năng method overloading: Cho chúng ta tạo ra các phương thức trùng tên nhưng khác nhau về danh sách tham số hay kiểu dữ liệu của tham số. 89
  89. Thân của lớp Method overloading • Khác kiểu tham số class SomeClass { public void WriteData(string data) { Console.WriteLine(data); } public void WriteData(int resource) { Console.WriteLine(resource); } } 90
  90. Thân của lớp Method overloading • Khác về thứ tự các kiểu tham số class SomeClass { public void WriteData(string data, int resource) { Console.WriteLine(data + “ ” + resource); } public void WriteData(int resource, string data) { Console.WriteLine(resource + “ ” + data); } } 91
  91. Thân của lớp Method overloading • Khác nhau giữa ref hay out class SomeClass { public void WriteData(string data) { Console.WriteLine(data); } public void WriteData(ref string data) { Console.WriteLine(data); } } 92
  92. Thân của lớp Method overloading • Khác nhau giữa ref và out class SomeClass { public void WriteData(ref string data) { Console.WriteLine(data); } public void WriteData(out string data) { data = “Empty”; Console.WriteLine(data); } } 93
  93. Thân của lớp Phương thức Toán tử • Operator Overloading • Toán tử 1 ngôi + - ! ~ ++ true false • Toán tử 2 ngôi + - * / % & | ^ > == != > = <= 94
  94. Thân của lớp Phương thức Toán tử • Cú pháp public static retval operator op (object1 [,object2]) ▪ Quy tắc tạo phương thức toán tử • Tất cả các phương thức toán tử được định nghĩa: public static • Kiểu trả về là bất kỳ kiểu nào (thông thường là kiểu mà phương thức đang định nghĩa. Ngoại lệ, toán tử true, false luôn trả về kiểu bool) • Số lượng tham số phụ thuộc vào số ngôi của toán tử • Nếu toán tử 1 ngôi, tham số của phương thức có kiểu là lớp đang định nghĩa toán tử 95
  95. Thân của lớp Phương thức Toán tử • Cú pháp public static retval operator op (object1 [,object2]) • Nếu toán tử 2 ngôi, tham số đầu tiên của phương thức có kiểu là lớp đang định nghĩa • Khi overload toán tử 2 ngôi, phép gán kết hợp của toán tử đó được tự động overload • Toán tử so sánh (>, =, <=, ==, !=) phải overload từng cặp • Nếu toán tử == và != được overload → phải overload phương thức Equals() và GetHashCode() 96
  96. Thân của lớp Phương thức Toán tử using System; public class Distance { int longitude, latitude; public Distance() { longitude = 0; latitude = 0; } public Distance(int longitude, int latitude) { this.longitude = longitude; this.latitude = latitude; } public static Distance operator - (Distance first, Distance second) { return new Distance(first.longitude - second.longitude, first.latitude - second.latitude); } } 97
  97. Thân của lớp Phương thức Constructor • Constructor • Cú pháp class ClassName { public ClassName( ) { } } • Chú ý – Construtor được gọi tự động khi một instance của lớp được tạo – Các constructor có thể được đa năng hóa để cung cấp sự đa dạng cho việc khởi tạo đối tượng. – Phương thức constructor có thể gọi các phương thức construtor khác 98
  98. Thân của lớp Phương thức Constructor Có ba dạng 1. Mặc định (default constructor): ClassName () 2. Sao chép (copy constructor): ClassName (ClassName) 3. Tham số (parameter constructor): ClassName (ds tham số) 99
  99. Thân của lớp Phương thức Destructor • Destructor • Cú pháp class ClassName { public ~ClassName() { } } • Chú ý – Không có bất kỳ tham số nào – Được gọi bởi Garbage Collector - GC 100
  100. Thân của lớp Thành viên tĩnh • Cú pháp tĩnh class ClassName { public static type variableName; public static type MethodName( ) { } public static type PropertyName { get { } set { } } public static event EventType EventName; } 101
  101. Thân của lớp Thành viên tĩnh • Thành viên tĩnh – static (method, property, field, event) • Các thành viên tĩnh có thể gọi trên một lớp ngay cả khi không có instance nào được tạo ra • Không thể dùng các instance để truy cập các thành viên tĩnh • Chỉ có một bản sao của field tĩnh và event tĩnh tồn tại • Các method tĩnh và property tĩnh chỉ có thể truy cập các field tĩnh và event tĩnh 102
  102. Thân của lớp Thành viên tĩnh • Cú pháp: Gọi field và phương thức tĩnh ClassName.variableName; ClassName.MethodName( ); ClassName.PropertyName; ClassName.EventName; • Chú ý – Nếu không khai báo public thì thành viên tĩnh chỉ được dùng cho các phương thức của lớp. – Nếu phương thức gọi thành viên tĩnh trong cùng lớp thì dùng tên thành viên tĩnh không cần thông qua tên lớp 103
  103. Thân của lớp Field hằng • Field hằng • Field hằng là một field có giá trị không thay đổi trong chu kỳ sống của đối tượng • Ví dụ: const int x = 5; • Quy tắc: • Field hằng là field có giá trị được thiết lập lúc biên dịch • Field hằng mặc nhiên là tĩnh 104
  104. Thân của lớp Field Read-Only • Field Read-Only • Giống như field hằng nhưng giá trị có thể được trì hoãn cho đến khi chương trình bắt đầu chạy (khi đối tượng của lớp chứa field được tạo) • Giá trị của field được khởi tạo trong constructor hay khi khai báo class CaptureApp { public readonly uint data = (uint)DateTime.Now.Ticks; public readonly int screenColor; public CaptureApp() { screenColor=65536; } } 105
  105. Thân của lớp Constructor tĩnh • Constructor tĩnh • Constructor tĩnh là constructor được dùng để khởi tạo bất kỳ dữ liệu static nào hay thực hiện một hành động chỉ thực hiện một lần class CaptureApp { public readonly int screenColor; static CaptureApp() { screenColor=65536; } } 106
  106. Thân của lớp Constructor tĩnh • Quy tắc của constructor tĩnh • Chỉ có duy nhất một constructor tĩnh • Không có tham số hay access modifier • Không thể truy cập thành viên không tĩnh (kể cả con trỏ this) • Được gọi trước khi instance đầu tiên được tạo ra hay các thành viên static được dùng 107
  107. Đối tượng • Tạo đối tượng với từ khóa new • Khai báo một biến class • Cú pháp ; • Tạo một đối tượng – Cú pháp = new ( ); = new ( ); 108
  108. Đối tượng • Truy cập thành viên public • Cú pháp ObjectName.Method(params); ObjectName.Field; • Đối tượng this – Cú pháp this.member 109
  109. Bài tập Cho lớp phân số (PhanSo) gồm 2 fields: tu va mau • Định nghĩa các constructor: default, parameter và copy • Định nghĩa các operator: +, -, *, / và so sánh >, =, <=, ==, != giữa 2 phân số 110
  110. Thừa kế
  111. Định nghĩa thừa kế • Thừa kế • Thừa kế cho chúng ta tạo ra lớp mới bằng cách tái sử dụng, mở rộng và chỉnh sửa hành vi đã được định nghĩa trong lớp khác • Cú pháp class DerivedClass : BaseClass { } ▪ Đơn thừa kế • C# không hỗ trợ đa thừa kế thông qua dẫn xuất • Tập hợp các đặc tính hành vi của các thực thể được hiện thực bằng đa thừa kế giao diện 112
  112. Gọi Construtor • Mặc nhiên, Constructor không tham số của lớp cơ sở được gọi trước constructor của lớp dẫn xuất • Quyết định lớp nào và constructor nào muốn gọi: • base( ) • this( ) class ClassName:BaseClass { public ClassName(type obj, ):base( ) { .} public ClassName(type obj, ):this( ) { .} } 113
  113. Phương thức “new” • Phương thức trong lớp cơ sở và lớp dẫn xuất có thể trùng tên class Token { ⋮ public string Name() { } } class IdentifierToken : Token { ⋮ public string Name() { } } ▪ Trình biên dịch sinh ra warning message cảnh báo IdentifierToken.Name ẩn Token.Name 114
  114. Phương thức “new” • new được dùng để ẩn đi thành viên được thừa kế từ lớp cơ sở class Token { ⋮ public string Name() { } } class IdentifierToken : Token { ⋮ new public string Name() { } } 115
  115. Phương thức “new” static void Method(Token t) { Console.WriteLine(t.Name()); } static void Main() { IdentifierToken variable = new IdentifierToken("variable"); Method(variable); } 116
  116. Bài tập - Cài đặt các lớp dùng “new” 117
  117. Phương thức “virtual” • Phương thức virtual là phương thức cho phép các lớp con hiện thực lại tùy theo chức năng của lớp con • Virtual không thể được dùng với static và override Đây là phiên bản hiện thực đầu tiên của phương thức Name() class Token { ⋮ public virtual string Name() { } } 118
  118. Phương thức “virtual” • virtual được dùng để định nghĩa phương thức hỗ trợ đa hình • Các lớp con hiện thực phiên bản mới của phương thức virtual đã định nghĩa trong lớp cha bằng cách dùng từ khóa override 119
  119. Phương thức “override” • Một phương thức override cung cấp một thực thi mới cho phương thức của lớp cơ sở. Phương thức lớp cơ sở nên khai báo là virtual • Access modifier của phương thức cơ sở không thể bị thay đổi bởi phương thức override nó • Từ khóa new, static, virtual không thể được dùng cùng override 120
  120. Phương thức “override” Hiện thực khác của phương thức Name() class IdentifierToken : Token { ⋮ public override string Name() { } } 121
  121. Phương thức “override” • Phương thức private không thể là virtual hay override • Hai phương thức phải: cùng tên, cùng kiểu và số lượng tham số, cùng kiểu trả về • Hai phương thức phải cùng kiểu truy cập • Chỉ có thể override phương thức virtual • override ngầm hiểu là virtual → có thể override ở những phương thức con tiếp theo 122
  122. Phương thức “sealed” class X { • Từ khóa sealed public void Method1() { } chỉ ra phương virtual public void Method2() { } thức không được } class Y : X override trong lớp { sealed override public void Method2() con của nó { } } class Z : Y { override public void Method2() { } } 123
  123. Bài tập - Cài đặt các lớp dùng “virtual - override” 124
  124. Đa hình • Thực hiện các bước sau: • Phương thức trong lớp cha là phương thức virtual, override hay abstract • Phương thức trong lớp con là phương thức override 125
  125. Đa hình • Cú pháp class ClassName1 { 1 virtual public type Method( ) { } } class ClassName2: ClassName1 { 2 override public type Method( ) { } } 126
  126. Lớp sealed và abstract • Lớp trừu tượng • Lớp trừu tượng là lớp được khai báo để làm lớp cơ sở cho lớp khác. Trừu ▪ Cú pháp tượng abstract class ClassName { } 127
  127. Lớp sealed và abstract • Chú ý: • Lớp trừu tượng không cho tạo đối tượng • Khai báo phương thức trừu tượng chỉ trong lớp trừu tượng • Thành viên trừu tượng không thể là static • Phương thức của Lớp trừu tượng không thể private • Phương thức trừu tượng không thể có modifier virtual 128
  128. Lớp sealed và abstract • Cú pháp: phương thức trừu tượng modifier abstract AbstractMethodName(); Trừu ▪ Hiện thực lớp trừu tượng tượng class ClassName:AbstractClassName { modifier AbstractMethodName() { } } 129
  129. Lớp sealed và abstract 1 using System; 2 abstract class BaseClass { public abstract void MethodA(); public void MethodB() { Console.WriteLine ("This is the non abstract method”); } } 3 class DerivedClass : BaseClass { public override void MethodA() { Console.WriteLine ("This is the abstract method overriden in derived class"); } } 130
  130. Lớp sealed và abstract class AbstractDemo { public static void Main() { DerivedClass objDerived = new DerivedClass(); BaseClass objBase = objDerived; objBase.MethodA(); objDerived.MethodB(); } } 131
  131. Lớp sealed và abstract • Lớp sealed • Là một lớp không bao giờ dùng làm lớp cơ sở • Lớp abstract không thể được dùng như là một lớp sealed sealed class Point { public Point(int x, int y) { this.x = x; this.y = y; } public int x; public int y; } 132
  132. Lớp static • Lớp static • Lớp static là lớp chỉ chứa các thành viên static, không thể tạo instance của lớp static và lớp static được nạp tự động bởi CLR • Đặc điểm của lớp static • Chỉ chứa thành viên static • Không thể tạo đối tượng • Là lớp sealed • Không chứa các instance constructor 133
  133. Lớp static static class CompanyInfo { public static string GetCompanyName() { return "CompanyName"; } public static string GetCompanyAddress() { return "CompanyAddress"; } // } 134
  134. Bài tập Trong một công ty X, các nhân viên thuộc một trong 2 bộ phân và gọi là: nhân viên kinh doanh và nhân viên sản xuất. Thông tin cơ bản của nhân viên gồm: Mã nhân viên, họ tên. Cách tính lương cho nhân viên mỗi bộ phận như sau: • Nhân viên kinh doanh: Ngoài mức lương cơ bản hàng tháng, nhân viên còn nhận được thêm 500.000/ hợp đồng được ký kết • Nhân viên sản xuất: Lương nhân viên sản xuất tính theo số lượng sản phẩm x 1000. Nếu làm trên 3000 sản phẩm sẽ được thưởng thêm 5% lương Viết chương trình tính lương cho các nhân viên 135
  135. Định nghĩa các phương thức sau class NhanVienSanXuat:NhanVien { private int soSanPham; public override void Nhap() { //Định nghĩa } public override void TinhLuong() { //Định nghĩa } } 137
  136. Định nghĩa các phương thức sau class NhanVienKinhDoanh:NhanVien { private int luongCB; private int soHDDaKy; public override void TinhLuong() { //Định nghĩa } } 138
  137. Cài đặt các phương thức sau class DanhSachNhanVien { List listNhanVien; public void Nhap() { //Định nghĩa } } 139
  138. Bài tập về nhà 1. Bổ sung các properties, constructors, các phương thức cần thiết khác trong các lớp trên 2. Viết phương thức Main() để chạy thử nghiệm kết quả 140
  139. Q&A 141141