Lập trình Windows 10/3/2018 1 C# NET nâng cao Lập trình Ứng dụng quản lý Nội dung Generic Delegate Events Anonymous Methods Lambda Expressions Exceptions 10/3/2018 2 Nội dung Generic Deleg[.]
Trang 1C#.NET nâng cao
Lập trình Ứng dụng quản lý
Nội dung
Generic Delegate
Events
Anonymous Methods
Lambda Expressions
Exceptions
Trang 2Nộ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 delegatenhư: Predicate<T>,
Action<T>, Comparison<T>,…
Trang 3Generic 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 [] array , Predicate < >
match )
Phương thức duyệt mảng
void Array ForEach < >( T [] array , Action < > action )
Phương thức sắp xếp
void Array Sort< >( T [] array , Comparison < > comparison )
Trang 4Cá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 ( );
}
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, Funccho 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.
Trang 5 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 đó Tlà các kiểu của tham số cần truyền vào và
TResultlà 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;
}
Trang 6Các method
Cho Func<string, ConsoleColor>
Cho Action<string, int>
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;
}
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);
}
Trang 7Nộ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
Eventkhô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
Trang 8Bả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 ();
eventTest1 ( );
else
Trang 9class 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
Sử dụng
delegate void EventHandler ( object sender,
EventArgs e)
class CTest
{
public event EventHandler EvtChangeHandler;
//
}
var c = new CTest ();
static void C_EvtChangeHandler( object sender, EventArgs e)
{
//
}
Trang 10Tạo Custom Event Arguments
Dẫn xuất EventArgs
Khai báo event phù hợp
Có dữ liệu cần thiết trong args
public class MyEventArgs : EventArgs
{
public string msg;
}
class CTest
{
public delegate void MyHandler ( object sender, MyEventArgs e);
public event MyHandler EvtMyHandler;
}
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
{
Trang 11Nộ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 ) {
//
};
}
Trang 12Truy 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
Trang 13Á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
Trang 14Lambda 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
in-linenhằ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
compilerbằng cách tự nhận diện kiểu của dữ liệu
Ngoà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 ;
Trang 15Ví dụ
Anonymous method
Dạng đầy đủ
Dạng rút gọn
var list = new List < int > { 3, 5, 7, 2, 10, 43, 12, 34 };
var evens = list.FindAll( delegate ( int i)
{
return (i % 2) == 0;
});
var evens = list.FindAll(i => (i % 2) == 0);
var evens = list.FindAll(( int i) => ((i % 2) == 0));
var evens = list.FindAll(( int i) => { return 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
Trang 16Truyền tham số trong Lambda Expression
Nhiều tham số
Không có tham số
var c = new CTest ();
c.EvtMyHandler += (sender, e) =>
{
Console WriteLine(e.msg);
};
Func < int > func = () => ( new Random ()).Next();
Nội dung
Generic Delegates
Events
Anonymous Methods
Lambda Expressions
Exceptions
Trang 17 Trong quá 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 soá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
}
catch ( Exception type )
{
//
}
…
finally
{
// thu hồi resources
Khi khối lệnh trong try phát sinh lỗi (quăng exception) thì khối catch tương ứng sẽ được xử lý.
Trang 18Ví dụ
static void Main ( string [] args )
{
try
{
int i = 0;
if ( Console ReadKey () KeyChar == ' ' )
{
int n = 10 / i
}
else
{
char c = Convert ToChar ( true );
}
}
catch ( DivideByZeroException e {
Console WriteLine ( Message);
}
catch ( InvalidCastException e {
Console WriteLine ( Message);
}
finally
{
Console WriteLine ( "finally " );
} }
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" );
}
Trang 19Cá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 URLtrang 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.