Lập trình Windows 9/18/2018 1 C# NET cơ bản phần tiếp theo Lập trình Ứng dụng quản lý Nội dung Một vài C# keyword Collections Generics Delegates 9/18/2018 2 Nội dung Một vài C# keyword Col[.]
9/18/2018 Lập trình Ứng dụng quản lý C#.NET phần Nội dung Một vài C# keyword Collections Generics Delegates 9/18/2018 Nội dung Một vài C# keyword Collections Generics Delegates C# keyword: partial Giúp chia class thành nhiều phần cài đặt File: SinhVien.Internal.cs partial class SinhVien { public string MSSV { get; set; } public string HoTen { get; set; } public string QueQuan { get; set; } public float DiemToan { get; set; } public float DiemAnhVan { get; set; } public float DiemTrietHoc { get; set; } } File: SinhVien.cs partial class SinhVien { public float GetDiemTrungBinh() { return (DiemToan + DiemAnhVan + DiemTrietHoc) / 3; } } 9/18/2018 C# keyword: as Chuyển đổi kiểu thực thực runtime, compile object o = new CTest(); Square s = (Square)o; Sử dụng as object o = new CTest(); var s = o as Square; if (s != null) { // } error??? o không thật Square o khơng thật Square kết trả null C# keyword: is Sử dụng trường hợp thể kế thừa class Shape { } class Shape2D : Shape { public string Name { get; set; } } class Square : Shape2D { public int Side { get; set; } } object o = new Square(); if (o is Shape2D) { ((Shape2D)o).Name = "A"; } if (o is Square) { ((Square)o).Side = 5; } 9/18/2018 Nội dung Một vài C# keyword Collections Generics Delegates Collections Collection kiểu liệu lưu trữ tập liệu (set of data) Trong NET cung cấp loại collection Nongeneric collections (namespace System.Collections) Generic collections (namespace System.Collections.Generic) 9/18/2018 ArrayList Kiểu liệu phần tử (item) object ArrayList strArray = new ArrayList(); strArray.AddRange(new string[] { "First", "Second", "Third" }); Console.WriteLine("This collection has {0} items.", strArray.Count); Console.WriteLine(); strArray.Add("Fourth!"); Console.WriteLine("This collection has {0} items.", strArray.Count); foreach (string s in strArray) { Console.WriteLine("Entry: {0}", s); } Console.WriteLine(); Vấn đề nongeneric Kiểm soát kiểu liệu khó khăn Hiệu phải chuyển đổi kiểu liệu nhiều lần value type reference type (boxing, unboxing) ArrayList al = new ArrayList(); al.Add(10); al.Add("10"); al.Add(new CTest()); foreach (int i in al) { Console.WriteLine(i); } error??? phần tử khơng thật tất int 9/18/2018 Nội dung Một vài C# keyword Collections Generics Delegates Generics Generic nghĩa “tổng quát” hàm ý đưa cách làm chung cho nhiều vấn đề Tình ví dụ cần xây dựng Ngăn xếp (Stack) chứa kiểu liệu int với phương thức như: push, pop, check,… Sau lại cần xây dựng Stack với phương thức liệu lại string Giải pháp cho vấn đề trên? public class IntStack { int[] _data = new int[100]; int _curIdx = -1; public void Push(int value) { _data[++_curIdx] = value; } public int Pop() { return _data[_curIdx ]; } } 9/18/2018 Giải pháp Cách thường làm: copy lại thay đổi kiểu liệu code Nếu có yêu cầu đổi kiểu liệu sang float, double,…??? Cách tốt biết đến kiểu liệu sở NET object Khi sử dụng kiểu liệu object Stack chấp nhận kiểu liệu? public class ObjectStack { object[] _data = new object[100]; int _curIdx = -1; public void Push(object value) { _data[++_curIdx] = value; } public object Pop() { return _data[_curIdx ]; } } Vấn đề Vấn đề ObjectStack kể dễ gây lỗi runtime (tức giải tốt mặt syntax) ObjectStack s = new ObjectStack(); //push vào kiểu string s.Push("test"); //lấy lại kiểu int int i = (int)s.Pop(); NET cung cấp giải pháp cho vấn đề thông qua khái niệm Generic 9/18/2018 Generic Types Generic tính NET Framework 2.0 và tích hợp sâu Common Language Runtime (CLR) Trong NET Framework, Generic giới thiệu khái niệm kiểu tham số dùng để thiết kế class method nhằm để trì hoãn kiểu liệu chúng khai báo khởi tạo Một điểm bật kiểu Generic cho phép kiểm tra cú pháp lúc biên dịch Có thể sử dụng nhiều kiểu liệu khác với đoạn code (tương tự khái niệm Template C++) Tham số T Bằng cách sử dụng tham số T tham số chung, cho phép tạo class sử dụng cho nhiều type khác public class GenericStack { T[] _data = new T[100]; int _curIdx = -1; public void Push(T value) { _data[++_curIdx] = value; } public T Pop() { return _data[_curIdx ]; } } // sử dụng GenericStack s = new GenericStack(); 9/18/2018 Generic Methods Là hàm thông dụng (cách hành xử chung cho type khác nhau) nên cài đặt theo kiểu Generic (sử dụng tham số đầu vào hay đầu generic) static void Swap(ref T x, ref T y) { T temp; temp = x; x = y; y = temp; } int iX = 2, iY = 6; float fX = 2.3f, fY = 6.7f; Swap(ref iX, ref iY); Swap(ref fX, ref fY); C# keyword: default Lấy giá trị mặc định với tính chất sau: Numeric values giá trị default Reference types giá trị default null Các Field gán default (nếu value type) null (nếu reference type) class GenericTest { T x, y; public GenericTest() { x = default(T); y = default(T); } } 9/18/2018 Constraining Type Parameters Ý nghĩa Generic Constraint where T : struct T áp dụng cho Value type where T : class T phải reference type where T : new() T phải type có default constructor where T : NameOfBaseClass T phải dẫn xuất từ class NameOfBaseClass where T : NameOfInterface T phải implement interface NameOfInterface class GenericTest where T : struct { T x, y; } GenericTest gti = new GenericTest(); error??? GenericTest gts = new GenericTest(); List Thuộc namespace System.Collections.Generic // khởi tạo var lP = new List { new CTest { X = 1, Y = }, new CTest(), new CTest { X = 7, Y = } }; // thêm phần tử lP.Add(new CTest { X = 4, Y = }); // thêm nhiều phần tử lP.AddRange(new CTest[] { new CTest(), new CTest() }); // duyệt for (int i = 0; i < lP.Count; i++) { Console.WriteLine("", lP[i].X, lP[i].Y); } 10 9/18/2018 Nội dung Một vài C# keyword Collections Generics Delegates Delegates Delegate kiểu liệu tham chiếu dùng để đóng gói phương thức với tham số kiểu trả xác định Với delegate chương trình thực thi động (dynamic) phương thức (method) khác trình chạy (runtime) Sau method đóng gói delegate, thực thi (called) delegate chạy (invoked) Khai báo delegate [modifiers] delegate ([parameter list]); 11 9/18/2018 Ví dụ // khai báo delegate delegate decimal ProcessCalculateHandler(decimal d1, decimal d2); static void Main(string[] args) { // tạo đối tượng delegate ProcessCalculateHandler pcA = new ProcessCalculateHandler(AddCalculate); TinhToan(pcA); } // method hợp với delegate khai báo static decimal AddCalculate(decimal d1, decimal d2) { return d1 + d2; } // phương thức có tham số delegate static void TinhToan(ProcessCalculateHandler pc) { if (pc != null) { Console.WriteLine("Ket qua: {0}", pc(123, 456)); } } Ứng dụng đơn giản Xét class SinhVien public class SinhVien { public string MSSV { get; set; } public string HoTen { get; set; } public string QueQuan { get; set; } } Với mảng đối tượng SinhVien SinhVien[] arrSV; Cần xếp mảng theo tiêu chí khác nhau, giải pháp??? 12 9/18/2018 Giải pháp Sử dụng hàm khác static void SapXepTheoMSSV(SinhVien[] arrSV) { for (int i = 0; i < arrSV.Length - 1; i++) { for (int j = i + 1; j < arrSV.Length; j++) { if (arrSV[i].MSSV.CompareTo(arrSV[j].MSSV) > 0) { SinhVien sv = arrSV[i]; arrSV[i] = arrSV[j]; arrSV[j] = sv; } } } } static void SapXepTheoHoTen(SinhVien[] arrSV) { // } static void SapXepTheoQueQuan(SinhVien[] arrSV) { // } Giải pháp Sử dụng delegate delegate int SoSanhHandler(SinhVien sv1, SinhVien sv2); static void SapXep(SinhVien[] arrSV, SoSanhHandler ssFunc) { for (int i = 0; i < arrSV.Length - 1; i++) { for (int j = i + 1; j < arrSV.Length; j++) { if (ssFunc(arrSV[i], arrSV[j]) > 0) { SinhVien sv = arrSV[i]; arrSV[i] = arrSV[j]; arrSV[j] = sv; } } } } 13 9/18/2018 Sử dụng delegate để gửi thông báo Xét yêu cầu quản lý cấp độ thẻ thành viên siêu thị Khi khách hàng tích lũy điểm nhờ mua hàng đến mức độ định nâng cấp độ thẻ siêu thị cần chúc mừng khách hàng Tìm giải pháp phù hợp??? class KhachHang class KhachHang { static uint muc1 = 20, muc2 = 30, muc3 = 50; public string HoTen { get; } public string CapDo { get; private set; } public uint DiemTichLuy { get; private set; } public KhachHang(string ht) { HoTen = ht; DiemTichLuy = 0; CapDo = "Cap0"; } public void TichDiem(uint dtl) { DiemTichLuy += dtl; if (DiemTichLuy >= muc3) { CapDo = "Cap3"; } // } } 14 9/18/2018 class SieuThi class SieuThi { List DsKhachHang = new List(); public void ThemKhachHang(KhachHang kh) { DsKhachHang.Add(kh); } public void ThucHienTichDiem() { var rd = new Random(); foreach (KhachHang kh in DsKhachHang) { kh.TichDiem((uint)rd.Next(1, 10)); } } public void ChucMungKH(KhachHang kh) { Console.WriteLine("{0} dat {1}", kh.HoTen, kh.CapDo); } } Hàm main static void Main(string[] args) { var st = new SieuThi(); st.ThemKhachHang(new KhachHang("ABC")); { st.ThucHienTichDiem(); // } while (Console.ReadKey().Key != ConsoleKey.Q); } 15 9/18/2018 Giải pháp Thêm cờ kiểm soát việc chúc mừng siêu thị class KhachHang public bool ChuaChucMung { get; set; } Thêm phương thức tổng duyệt khách hàng class SieuThi public void TongDuyetKH() { string cdHienTai = null; foreach (KhachHang kh in DsKhachHang) { if (kh.ChuaChucMung) { ChucMungKH(kh); kh.ChuaChucMung = false; } } } Hàm tích điểm public void TichDiem(uint dtl) { string cdOld = CapDo; DiemTichLuy += dtl; if (DiemTichLuy >= muc3) { CapDo = "Cap3"; } else if (DiemTichLuy >= muc2) { CapDo = "Cap2"; } else if (DiemTichLuy >= muc1) { CapDo = "Cap1"; } if (cdOld != CapDo) { ChuaChucMung = true; } } 16 9/18/2018 Hàm main static void Main(string[] args) { var st = new SieuThi(); st.DsKhachHang.Add(new KhachHang("ABC")); { Console.WriteLine("Tich diem "); st.ThucHienTichDiem(); st.TongDuyetKH(); } while (Console.ReadKey().Key != ConsoleKey.Q); } Giải pháp Tạo delegate cho KhachHang class KhachHang { public delegate void ThayDoiCapDoHandler(KhachHang kh); ThayDoiCapDoHandler handlers; public void TichDiem(uint dtl) { if (cdOld != CapDo) { if (handlers != null) { handlers(this); } } } public void DangKyTheoDoi(ThayDoiCapDoHandler h) { handlers = h; } } 17 9/18/2018 Thay đổi class SieuThi public void ThemKhachHang(KhachHang kh) { DsKhachHang.Add(kh); kh.DangKyTheoDoi(new KhachHang.ThayDoiCapDoHandler(ChucMungKH)); } Mục tiêu đăng ký theo dõi KhachHang tạo Hàm main không cần thay đổi… Đánh giá giải pháp? Về vấn đề nơi kiểm sốt để phát sinh thơng báo? Khi có số lượng lớn đối tượng phát sinh thơng báo? 18 9/18/2018 Multicasting Cơ chế multicasting cho phép gọi hai hay nhiều phương thức thực thi thông qua ủy quyền đơn Mục đích với delegate gọi thực nhiều phương thức Để thực kiểu trả delegate phải kiểu void Ví dụ: myMulticastDelegate = Writer + Logger; myMulticastDelegate += Transmitter; Ví dụ delegate void MultiHandler(decimal d1, decimal d2); static void Main(string[] args) { MultiHandler md = new MultiHandler(Func1); md += new MultiHandler(Func2); md(123, 456); } static void Func1(decimal d1, decimal d2) { Console.WriteLine("{0} + {1}= {2}", d1, d2, d1 + d2); } static void Func2(decimal d1, decimal d2) { Console.WriteLine("{0} - {1}= {2}", d1, d2, d1 - d2); } 19 9/18/2018 Áp dụng Xét lại ví dụ Siêu thị Khách hàng có thêm phận hay đối tác cần quan tâm đến việc thay đổi cấp độ khách hàng? Bộ phận khuyến cần gửi ưu đãi khuyến Đối tác Tài muốn tặng ưu đãi Thay đổi hàm đăng ký để áp dụng multicasting public void DangKyTheoDoi(ThayDoiCapDoHandler h) { handlers += h; } Xây dựng class CtyTaiChinh class CtyTaiChinh { static string TenCty = "CtyABC"; public static void UuDaiMoi(KhachHang kh) { Console.WriteLine("{0} uu dai moi cho {1}", TenCty, kh.HoTen); } } 20