10/3/2018
Lập trình Ứng dụng quản lý
C#.NET nâng cao
Nội dung
Generic Delegate
Events
Anonymous Methods
Lambda Expressions
Exceptions
1
10/3/2018
Nội dung
Generic Delegates
Events
Anonymous Methods
Lambda Expressions
Exceptions
Generic Delegates
Tương tự với method, delegate cũng có thể cài
đặt theo kiểu generic (nhằm làm tham số hàm
chung nhất cho một số trường hợp).
public delegate void MyDelegate<T>(T param);
Trong .NET được khai báo sẵn một số các
generic delegate như: Predicate<T>,
Action<T>, Comparison<T>,…
2
10/3/2018
Generic Delegates thông dụng
Predicate<T> được sử dụng để kiểm tra các giá
trị có thỏa mãn một điều kiện nào đó khơng và trả
về kiểu bool.
Action<T> sử dụng để thực hiện các hành động
với đối tượng mà ta truyền vào và không trả về
giá trị nào cả.
Comparison<T> dùng để so sánh hai đối tượng
cùng kiểu, thường sử dụng trong các trường hợp
sắp xếp.
…
Ví dụ thường gặp nhất là các phương thức tĩnh
được cung cấp trong class Array.
Ví dụ
class Array
Phương thức tìm kiếm
T[] Array.FindAll<T>(T[] array, Predicate<T>
match)
Phương thức duyệt mảng
void Array.ForEach<T>(T[] array, Action<T> action)
Phương thức sắp xếp
void Array.Sort<T>(T[] array, Comparison<T> comparison)
3
10/3/2018
Cách sử dụng
bool FuncPredicate(int value)
{
return value % 2 == 0;
}
StringBuilder sb = new StringBuilder();
void FuncAction(int value)
{
sb.AppendFormat("{0}, ", value);
}
int FuncComparison(int x, int y)
{
return x.CompareTo(y);
}
void funcTest()
{
int[] arrInt = new int[] { 3, 5, 7, 2, 10, 43, 12, 34 };
//sử dụng Predicate
int[] arrTemp = Array.FindAll<int>(arrInt, new
Predicate<int>(FuncPredicate));
//sử dụng Action
Array.ForEach(arrInt, new Action<int>(FuncAction));
//sử dụng Comparison
Array.Sort(arrInt, new Comparison<int>(FuncComparison));
}
Generic Delegates Action<> và Func<>
Từ C# 3.0, Microsoft cung cấp một kiểu delegate
mới linh hoạt và tiện dụng hơn là Action, Func.
Action, Func cho phép khai báo và tạo ra các
dạng delegate với số lượng tham số và kiểu trả
về khác nhau, tương tự như khi tạo ra một
method.
Action, Func được dùng chủ yếu để tạo và lưu
trữ một anonymous method ngắn gọn bằng
lambda expression và được sử dụng như
những method thông thường.
4
10/3/2018
Syntax
Cú pháp để sử dụng Action, Func là viết các kiểu
của tham số và giá trị trả về vào cặp ngoặc ‘<>’,
theo sau từ khóa Action, Func.
Action<T, T, ..., T>
Func<T, T, ..., TResult>
Trong đó T là các kiểu của tham số cần truyền vào và
TResult là kiểu của giá trị trả về.
Lưu ý là Func yêu cầu ít nhất một tham số trong cặp ‘<>’,
tức là phải có kiểu trả về. Khơng để đặt void hay để một
cặp ngoặc ‘<>’ rỗng khi dùng Func.
Ví dụ
static void DisplayMsg(string msg,
Func<string, ConsoleColor> func,
Action<string, int> action)
{
ConsoleColor previous = Console.ForegroundColor;
if (func != null)
{
Console.ForegroundColor = func(msg);
}
int count = (new Random()).Next(2, 5);
if (action != null)
{
action(msg, count);
}
Console.ForegroundColor = previous;
}
5
10/3/2018
Các method
Cho Func<string, ConsoleColor>
static ConsoleColor GetColor(string msg)
{
if (msg.Length >= 10)
return ConsoleColor.Red;
if (msg.Length >= 7)
return ConsoleColor.Yellow;
if (msg.Length >= 4)
return ConsoleColor.Blue;
return ConsoleColor.White;
}
Cho Action<string, int>
static void PrintMsg(string msg, int count)
{
for (int i = 0; i < count; i++)
{
Console.WriteLine(msg);
}
}
Hàm main
static void Main(string[] args)
{
var func = new Func<string, ConsoleColor>(GetColor);
var action = new Action<string, int>(PrintMsg);
DisplayMsg("Test
Test", func, action);
}
6
10/3/2018
Nội dung
Generic Delegates
Events
Anonymous Methods
Lambda Expressions
Exceptions
Events
Event (sự kiện) là các hành động xảy ra trong
quá trình chạy chương trình (gõ phím, click chuột,
nhấn nút,…) và được thơng báo để được xử lý
thích hợp.
Event khơng thể biết trước chính xác khi nào xảy
ra, điều quan trọng là phải được xử lý thích hợp
khi nó xảy ra.
Cơ chế publishing và subscribing nghĩa là mỗi
đối tượng đều có thể publish một tập hợp các
event để các lớp khác nếu cần xử lý khi nó xảy
ra thì có thể đăng ký (subscribe) vào danh sách
nhận và như vậy mỗi khi lớp publish phát sinh
một event thì tất cả các lớp đã đăng ký sẽ được
nhận thông báo.
7
10/3/2018
Bản chất
Trong .NET cơ chế event được thực thi với
những delegate.
Lớp publisher định nghĩa một delegate và
những lớp subscriber phải thực thi. Khi một sự
kiện xuất hiện thì phương thức của lớp
subscriber được gọi thông qua delegate.
Một phương thức được dùng để xử lý các sự
kiện thì được là trình xử lý sự kiện (event
handler).
Khai báo:
public delegate void myEventHandler();
public event myEventHandler myEvent;
hoặc
public EventHandler myEvent;
Ví dụ
class TestEvent
{
public delegate void TestHandler(int n);
public event TestHandler eventTest1, eventTest2;
public void Run()
{
Random rd = new Random();
while (true)
{
int n = rd.Next();
if (n % 2 == 0)
eventTest1(n);
else
eventTest2(n);
if (Console.ReadKey().KeyChar == 'q')
return;
}
}
}
8
10/3/2018
class Program
{
static void Main(string[] args)
{
TestEvent t = new TestEvent();
t.eventTest1 += t_eventTest1;
t.eventTest2 += t_eventTest2;
t.Run();
}
static void t_eventTest2(int n)
{
Console.WriteLine("Le: {0}", n);
}
static void t_eventTest1(int n)
{
Console.WriteLine("Chan: {0}", n);
}
}
EventHandler
Được cung cấp sẵn bởi .NET
Là event cơ bản với delegate được định nghĩa
delegate void EventHandler(object sender,
EventArgs e)
Sử dụng
class CTest
{
public event EventHandler EvtChangeHandler;
//...
}
static void C_EvtChangeHandler(object sender, EventArgs e)
{
//...
}
var c = new CTest();
c.EvtChangeHandler += C_EvtChangeHandler;
9
10/3/2018
Tạo Custom Event Arguments
Dẫn xuất EventArgs
public class MyEventArgs : EventArgs
{
public string msg;
}
Khai báo event phù hợp
class CTest
{
public delegate void MyHandler(object sender, MyEventArgs e);
public event MyHandler EvtMyHandler;
}
Có dữ liệu cần thiết trong args
private static void C_EvtMyHandler(object sender, MyEventArgs e)
{
Console.WriteLine(e.msg);
}
EventHandler<T>
Mặc định có sẵn trong .NET
Là dạng generic delegate
Cho phép sử dụng event mặc định với custom
event arguments
public class MyEventArgs : EventArgs
{
public string msg;
}
class CTest
{
//public delegate void MyHandler(object sender, MyEventArgs e);
//public event MyHandler EvtMyHandler;
public event EventHandler<MyEventArgs> EvtMyHandler;
}
10
10/3/2018
Nội dung
Generic Delegates
Events
Anonymous Methods
Lambda Expressions
Exceptions
Anonymous Methods
Anonymous method (tạm dịch là phương thức vô
danh) là phương thức khơng có tên được khai báo
với từ khóa delegate.
Anonymous method cho phép tạo ra các hành động
cho một delegate với cách viết inline.
Cụ thể
delegate void DelTest(int value);
void funcTest()
{
DelTest dt = delegate(int value)
{
//...
};
}
11
10/3/2018
Truy xuất biến cục bộ
Anonymous method không thể truy xuất tham
số ref hay out của method cha.
Anonymous method khơng được có biến cục bộ
cùng tên với biến của method cha.
Anonymous method có thể truy xuất thành phần
dữ liệu của class chứa nó.
Anonymous method có thể dùng tên biến chung
với thành phần dữ liệu của class chứa nó.
Áp dụng trong các Generic Delegate
static void funcTest()
{
var sb = new StringBuilder();
int[] arrInt = new int[] { 3, 5, 7, 2, 10, 43, 12, 34 };
//sử dụng Predicate
int[] arrTemp = Array.FindAll<int>(arrInt,
delegate (int value) {
return value % 2 == 0;
});
//sử dụng Action
Array.ForEach(arrInt, delegate (int value) {
sb.AppendFormat("{0}, ", value);
});
//sử dụng Comparison
Array.Sort(arrInt, delegate (int x, int y) {
return x.CompareTo(y);
});
}
12
10/3/2018
Áp dụng cho callback method
static void Main(string[] args)
{
var c = new CTest();
c.EvtMyHandler += delegate (object sender, MyEventArgs e)
{
Console.WriteLine(e.msg);
};
c.EvtMyHandler += delegate (object sender, MyEventArgs e)
{
var str = e.msg.ToUpper();
Console.WriteLine(str);
};
}
Nội dung
Generic Delegates
Events
Anonymous Methods
Lambda Expressions
Exceptions
13
10/3/2018
Lambda Expressions
Có từ C# 3.0
Có thể nói so với anonymous method, lambda
expression được coi là một sự cải tiến đáng giá từ
phiên bản C# 2.0 lên C# 3.0.
Khi dùng anonymous method có thể tạo các hàm inline nhằm hạn chế việc khai báo các hàm riêng lẻ
không cần thiết, giúp mã lệnh ngắn gọn hơn.
Với lambda expression thì có thể viết ngắn gọn và
dễ dàng hơn nhờ việc cung cấp toán tử và cú pháp
mới, đồng thời thể hiện sự “thông minh” của
compiler bằng cách tự nhận diện kiểu của dữ liệu.
Ngồi ra, đây cịn là kĩ thuật để tạo ra các kiểu
expression tree.
Syntax
Dạng của Lambda Expression như sau:
(input parameters) => expression
Dấu mở và đóng ngoặc là tùy chọn trong trường hợp chỉ
có 1 tham số, ngược lại nó là bắt buộc.
Nếu có nhiều hơn 1 tham số thì chúng sẽ được phân
cách bằng dấu phẩy (,).
Kiểu dữ liệu của các tham số có thể được khai báo
tường minh hoặc khơng. Nếu khơng khai báo, trình biên
dịch sẽ tự xác định kiểu, tuy nhiên trong một số trường
hợp, cần phải chỉ rõ kiểu dữ liệu.
//sẽ báo lỗi
s => s.Length;
//cần khai báo kiểu dữ liệu
(string s) => s.Length;
14
10/3/2018
Ví dụ
Anonymous method
var list = new List<int> { 3, 5, 7, 2, 10, 43, 12, 34 };
var evens = list.FindAll(delegate (int i)
{
return (i % 2) == 0;
});
Dạng đầy đủ
var evens = list.FindAll((int i) => { return i % 2 == 0; });
Dạng rút gọn
var evens = list.FindAll((int i) => ((i % 2) == 0));
var evens = list.FindAll(i => (i % 2) == 0);
Đặc điểm
Kiểu dữ liệu của tham số có thể khai báo tường
minh hoặc khơng tường minh.
Có thể sử dụng {} hoặc () để bọc khối lệnh. Có
sự khác biệt giữa 2 loại???
Có thể loại bỏ cặp dấu bọc khối lệnh khi không
cần thiết.
15
10/3/2018
Truyền tham số trong Lambda Expression
Nhiều tham số
var c = new CTest();
c.EvtMyHandler += (sender, e) =>
{
Console.WriteLine(e.msg);
};
Khơng có tham số
Func<int> func = () => (new Random()).Next();
Nội dung
Generic Delegates
Events
Anonymous Methods
Lambda Expressions
Exceptions
16
10/3/2018
Exceptions
Trong q trình chương trình chạy có rất nhiều
trường hợp xảy ra lỗi không thể biết trước như:
lỗi chia 0, lỗi sử dụng đối tượng null, lỗi đọc file
không tồn tại (hoặc đã bị xóa),…
Để kiểm sốt và xử lý các lỗi như trên thì .NET
định nghĩa class Exception và cách thức xử lý
(exception handling).
Khối lệnh xử lý exception (try…catch…finally)
try
{
// khối lệnh có thể phát sinh lỗi
}
catch (Exception type)
{
// xử lý lỗi
Khi khối lệnh trong try phát sinh
}
lỗi (quăng exception) thì khối
catch (Exception type)
catch tương ứng sẽ được xử lý.
{
// ...
}
…
finally
{
// thu hồi resources
}
17
10/3/2018
Ví dụ
static void Main(string[] args)
catch (DivideByZeroException e)
{
{
Console.WriteLine(e.Message);
try
}
{
catch(InvalidCastException e)
int i = 0;
{
if (Console.ReadKey().KeyChar == ' ')
Console.WriteLine(e.Message);
{
}
int n = 10 / i;
finally
}
{
else
Console.WriteLine("finally...");
}
{
char c = Convert.ToChar(true);
}
}
}
Throw exception
Có thể tự quăng ra exception cho bên ngoài xử lý.
static void Main(string[] args)
{
try
{
if (Console.ReadKey().KeyChar == ' ')
{
Console.WriteLine("normal...");
}
else
{
Console.WriteLine("error");
throw new Exception("need fix");
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
18
10/3/2018
Các property thông dụng
Property TargetSite: cung cấp thông tin chi tiết
của method phát sinh exception.
Property StackTrace: cung cấp thông tin theo dõi
nơi phát sinh exception.
Property HelpLink: cho phép sử dụng cung cấp
thông tin URL trang trợ giúp.
Property Data: cho phép sử dụng lưu trữ thông
tin dạng IDictionary.
Bài tập
Thực hiện lại ví dụ về Siêu thị với Khách hàng
bằng cách sử dụng event.
Khách hàng cần thêm các thông tin: địa chỉ, ngày
sinh.
Thêm các chức năng:
Tìm kiếm khách hàng theo các tiêu chí: họ tên, năm sinh,
địa chỉ.
Cộng điểm cho các khách hàng có sinh nhật trong tháng.
Sắp xếp các khách hàng theo địa chỉ rồi theo điểm tích lũy.
19