Post

Delegate in C# - Part 2

Introduction

Trong phần 2 của series bài viết này, tôi sẽ trình bày sâu hơn về cách sử dụng delegate thật linh hoạt, mang lại hiệu quả tối ưu. Nếu bạn chưa đọc bài viết đầu tiên trong series này, tôi khuyên bạn hãy làm một việc – đọc bài viết đó tại đây.

Ở phần này, tôi muốn thảo luận về những cách khác có thể để gọi một function thông qua delegate. Nội dung chính mà tôi muốn xoáy vào đó là làm thế nào để gọi một delegate không đồng thời. Việc này đòi hỏi một vài kĩ thuật nâng cao, bởi vì nó sẽ tạo ra một thread khác. Tôi hi vọng sau khi đã hiểu kĩ về nội dung của bài viết này, bạn có thể tự tin sử dụng nó trong các ứng dụng của bạn.

Life Problem

Trong bài viết này, tôi muốn đưa những vấn đề thực sự trong cuộc sống vào làm ví dụ, vì theo tôi nghĩ nó sẽ dễ hiểu hơn. Vấn đề của chúng ta hôm nay như sau:

Tối hôm nay, tôi sẽ mời một vài người bạn của tôi đến tham dự một bữa tiệc, và tôi sẽ cần phải chuẩn bị một số thứ để bữa tiệc có thể diễn ra. Sau đây là danh sách những công việc cần thiết:

  1. Dọn phòng

  2. Làm một ít thức ăn

  3. Chuẩn bị bàn

  4. Tắm rửa, thay quần áo…

Những việc này cũng không nặng nhọc lắm, nhưng khổ một nỗi là tôi không biết nấu ăn. Vì vậy tôi cần phải tìm một cách nào đó thôi :D. Một giải pháp đó là order cho một nhà hàng nào đó qua điện thoại. Nhà hàng mà tôi chọn có một vài điểm đặc biệt. Nếu muốn, họ có thể chuẩn bị thức ăn ngay tại nhà của bạn. Họ sẽ chuyển nguyên liệu tới nhà bạn và nấu ăn tại đó. Vậy là bạn có thể xem người ta nấu ăn trực tiếp rồi. Một lựa chọn khác là bạn có thể yêu cầu họ làm sẵn tại nhà hàng, sau đó chuyển thức ăn đã làm xong tới cho bạn.

Program Model

Bây giờ, chúng ta sẽ giả lập tình huống này thành một chương trình.

Đầu tiên, tôi tạo class Restaurant với một phương thức tĩnh MakeFood, nó sẽ nhận order dưới dạng string, đồng thời return một chuỗi khi công việc đã xong. Quá trình này có thể tốn nhiều thời gian, do đó tôi sử dụng thêm phương thức Thread.Sleep:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<span style="color:#0600ff;font-weight:bold;">public</span> <span style="color:#6666cc;font-weight:bold;">class</span> Restaurant
<span style="color:#008000;">{</span>
	<span style="font-style:italic;color:#008080;">/// <summary></span>
	<span style="font-style:italic;color:#008080;">/// Static function excepts an order and delivers some food</span>
	<span style="font-style:italic;color:#008080;">/// </summary></span>
	<span style="font-style:italic;color:#008080;">/// <param name="order"></span>
	<span style="font-style:italic;color:#008080;">/// <returns></span>
	<span style="color:#0600ff;font-weight:bold;">public</span> <span style="color:#0600ff;font-weight:bold;">static</span> <span style="color:#6666cc;font-weight:bold;">string</span> MakeFood<span style="color:#008000;">(</span><span style="color:#6666cc;font-weight:bold;">string</span> order<span style="color:#008000;">)</span>
	<span style="color:#008000;">{</span>
		<span style="font-style:italic;color:#008080;">//register start:</span>
		Console<span style="color:#008000;">.</span><span style="color:#0000ff;">WriteLine</span><span style="color:#008000;">(</span><span style="color:#666666;">"Making {0} started at {1}"</span>, order, 
				DateTime<span style="color:#008000;">.</span><span style="color:#0000ff;">Now</span><span style="color:#008000;">.</span><span style="color:#0000ff;">ToLongTimeString</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//food preparation:</span>
		Thread<span style="color:#008000;">.</span><span style="color:#0000ff;">Sleep</span><span style="color:#008000;">(</span><span style="color:#ff0000;">4000</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//register finish</span>
		Console<span style="color:#008000;">.</span><span style="color:#0000ff;">WriteLine</span><span style="color:#008000;">(</span><span style="color:#666666;">"Making {0} finished at {1}"</span>, order, 
				DateTime<span style="color:#008000;">.</span><span style="color:#0000ff;">Now</span><span style="color:#008000;">.</span><span style="color:#0000ff;">ToLongTimeString</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//deliver:</span>
		<span style="color:#0600ff;font-weight:bold;">return</span> order<span style="color:#008000;">.</span><span style="color:#0000ff;">ToUpper</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span> <span style="color:#008000;">+</span> <span style="color:#666666;">" made"</span><span style="color:#008000;">;</span>
	<span style="color:#008000;">}</span>
<span style="color:#008000;">}</span>

Tiếp theo, class PartyHost bao gồm một vài phương thức public, đó là các công việc phải làm trước khi buổi tiệc bắt đầu. Tất cả các function đều được xác định rõ thời điểm bắt đầu và kết thúc. Tôi cũng thêm một vài khoảng thời gian chờ đợi nhằm giải lập thời gian thực mà chúng ta cần để hoàn thành công việc. Class này có function MakeFood, thay vào đó, một delegate có tên là Restaurant sẽ gọi function MakeFood. Trong thực tế, delegate chính là cái điện thoại tôi dùng để order thức ăn.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<span style="color:#0600ff;font-weight:bold;">public</span> <span style="color:#6666cc;font-weight:bold;">class</span> PartyHost
<span style="color:#008000;">{</span>
	<span style="font-style:italic;color:#008080;">/// <summary></span>
	<span style="font-style:italic;color:#008080;">/// Person Name</span>
	<span style="font-style:italic;color:#008080;">/// </summary></span>
	<span style="color:#0600ff;font-weight:bold;">public</span> <span style="color:#6666cc;font-weight:bold;">string</span> Name <span style="color:#008000;">{</span> get<span style="color:#008000;">;</span> <span style="color:#0600ff;font-weight:bold;">private</span> set<span style="color:#008000;">;</span> <span style="color:#008000;">}</span>   <span style="font-style:italic;color:#008080;">/// <summary></span>
	<span style="font-style:italic;color:#008080;">/// constructor</span>
	<span style="font-style:italic;color:#008080;">/// </summary></span>
	<span style="font-style:italic;color:#008080;">/// <param name="name"></span>
	<span style="color:#0600ff;font-weight:bold;">public</span> PartyHost<span style="color:#008000;">(</span><span style="color:#6666cc;font-weight:bold;">string</span> name<span style="color:#008000;">)</span>
	<span style="color:#008000;">{</span>
		<span style="color:#0600ff;font-weight:bold;">this</span><span style="color:#008000;">.</span><span style="color:#0000ff;">Name</span> <span style="color:#008000;">=</span> name<span style="color:#008000;">;</span>
	<span style="color:#008000;">}</span>   <span style="font-style:italic;color:#008080;">/// <summary></span>
	<span style="font-style:italic;color:#008080;">/// Clean up place for party</span>
	<span style="font-style:italic;color:#008080;">/// </summary></span>
	<span style="color:#0600ff;font-weight:bold;">public</span> <span style="color:#6666cc;font-weight:bold;">void</span> CleanUpPlace<span style="color:#008000;">(</span><span style="color:#008000;">)</span>
	<span style="color:#008000;">{</span>
		<span style="font-style:italic;color:#008080;">//register start:</span>
		Console<span style="color:#008000;">.</span><span style="color:#0000ff;">WriteLine</span><span style="color:#008000;">(</span><span style="color:#666666;">"Cleaning  started at {0}"</span>, 
				DateTime<span style="color:#008000;">.</span><span style="color:#0000ff;">Now</span><span style="color:#008000;">.</span><span style="color:#0000ff;">ToLongTimeString</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//cleaning:</span>
		Thread<span style="color:#008000;">.</span><span style="color:#0000ff;">Sleep</span><span style="color:#008000;">(</span><span style="color:#ff0000;">3000</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//register end:</span>
		Console<span style="color:#008000;">.</span><span style="color:#0000ff;">WriteLine</span><span style="color:#008000;">(</span><span style="color:#666666;">"Cleaning  finished at {0}"</span>, 
				DateTime<span style="color:#008000;">.</span><span style="color:#0000ff;">Now</span><span style="color:#008000;">.</span><span style="color:#0000ff;">ToLongTimeString</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>
	<span style="color:#008000;">}</span>   <span style="font-style:italic;color:#008080;">/// <summary></span>
	<span style="font-style:italic;color:#008080;">/// Set up furniture for the party</span>
	<span style="font-style:italic;color:#008080;">/// </summary></span>
	<span style="color:#0600ff;font-weight:bold;">public</span> <span style="color:#6666cc;font-weight:bold;">void</span> SetupFurniture<span style="color:#008000;">(</span><span style="color:#008000;">)</span>
	<span style="color:#008000;">{</span>
		<span style="font-style:italic;color:#008080;">//register start:</span>
		Console<span style="color:#008000;">.</span><span style="color:#0000ff;">WriteLine</span><span style="color:#008000;">(</span><span style="color:#666666;">"Furniture setup  started at {0}"</span> , 
				DateTime<span style="color:#008000;">.</span><span style="color:#0000ff;">Now</span><span style="color:#008000;">.</span><span style="color:#0000ff;">ToLongTimeString</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//setting up:</span>
		Thread<span style="color:#008000;">.</span><span style="color:#0000ff;">Sleep</span><span style="color:#008000;">(</span><span style="color:#ff0000;">2000</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//register end:</span>
		Console<span style="color:#008000;">.</span><span style="color:#0000ff;">WriteLine</span><span style="color:#008000;">(</span><span style="color:#666666;">"Furniture setup  finished at {0}"</span>, 
				DateTime<span style="color:#008000;">.</span><span style="color:#0000ff;">Now</span><span style="color:#008000;">.</span><span style="color:#0000ff;">ToLongTimeString</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>
	<span style="color:#008000;">}</span>   <span style="font-style:italic;color:#008080;">/// <summary></span>
	<span style="font-style:italic;color:#008080;">/// Take your time</span>
	<span style="font-style:italic;color:#008080;">/// </summary></span>
	<span style="color:#0600ff;font-weight:bold;">public</span> <span style="color:#6666cc;font-weight:bold;">void</span> TakeBathAndDressUp<span style="color:#008000;">(</span><span style="color:#008000;">)</span>
	<span style="color:#008000;">{</span>
		<span style="font-style:italic;color:#008080;">//register start:</span>
		Console<span style="color:#008000;">.</span><span style="color:#0000ff;">WriteLine</span><span style="color:#008000;">(</span><span style="color:#666666;">"TakeBathAndDressUp  started at {0}"</span>, 
				DateTime<span style="color:#008000;">.</span><span style="color:#0000ff;">Now</span><span style="color:#008000;">.</span><span style="color:#0000ff;">ToLongTimeString</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//having fun:</span>
		Thread<span style="color:#008000;">.</span><span style="color:#0000ff;">Sleep</span><span style="color:#008000;">(</span><span style="color:#ff0000;">2000</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//register end:</span>
		Console<span style="color:#008000;">.</span><span style="color:#0000ff;">WriteLine</span><span style="color:#008000;">(</span><span style="color:#666666;">"TakeBathAndDressUp  finished at {0}"</span>, 
				DateTime<span style="color:#008000;">.</span><span style="color:#0000ff;">Now</span><span style="color:#008000;">.</span><span style="color:#0000ff;">ToLongTimeString</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>
	<span style="color:#008000;">}</span>   <span style="font-style:italic;color:#008080;">/// <summary></span>
	<span style="font-style:italic;color:#008080;">/// Get restaurant's phone number</span>
	<span style="font-style:italic;color:#008080;">/// </summary></span>
	<span style="color:#0600ff;font-weight:bold;">public</span> OrderHandle GetRestaurantPhoneNumber<span style="color:#008000;">(</span><span style="color:#008000;">)</span>
	<span style="color:#008000;">{</span>
		<span style="font-style:italic;color:#008080;">//find the restaurant's phone number in the phone book:</span>
		OrderHandle phone <span style="color:#008000;">=</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="color:#008000;">new</span></a> OrderHandle<span style="color:#008000;">(</span>Restaurant<span style="color:#008000;">.</span><span style="color:#0000ff;">MakeFood</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="color:#0600ff;font-weight:bold;">return</span> phone<span style="color:#008000;">;</span>
	<span style="color:#008000;">}</span>
<span style="color:#008000;">}</span>

Bốn class tiếp theo là chương trình chính. Tất cả đều có hàm Main riêng. Nếu bạn để các class này vào cùng một project, bạn cần phải xác định hàm Main nào bạn muốn gọi trước khi chạy chương trình. Dưới đây là đoạn chương trình gọi delegate trực tiếp bằng phương thức Invoke. Cách gọi này chính là synchronous call.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<span style="color:#0600ff;font-weight:bold;">public</span> <span style="color:#6666cc;font-weight:bold;">class</span> Sync
<span style="color:#008000;">{</span>
	<span style="font-style:italic;color:#008080;">/// <summary></span>
	<span style="font-style:italic;color:#008080;">/// Invoking directly</span>
	<span style="font-style:italic;color:#008080;">/// </summary></span>
	<span style="font-style:italic;color:#008080;">/// <param name="args"></span>
	<span style="color:#0600ff;font-weight:bold;">static</span> <span style="color:#6666cc;font-weight:bold;">void</span> Main<span style="color:#008000;">(</span><span style="color:#6666cc;font-weight:bold;">string</span><span style="color:#008000;">[</span><span style="color:#008000;">]</span> args<span style="color:#008000;">)</span>
	<span style="color:#008000;">{</span>
		<span style="font-style:italic;color:#008080;">//mark start time:</span>
		<span style="color:#6666cc;font-weight:bold;">long</span> start <span style="color:#008000;">=</span> DateTime<span style="color:#008000;">.</span><span style="color:#0000ff;">Now</span><span style="color:#008000;">.</span><span style="color:#0000ff;">Ticks</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//initialize host</span>
		PartyHost host <span style="color:#008000;">=</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="color:#008000;">new</span></a> PartyHost<span style="color:#008000;">(</span><span style="color:#666666;">"Ed"</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//find a restaurant phone number in phone book;</span>
		<span style="font-style:italic;color:#008080;">//it is your delegate:</span>
		OrderHandle restaurantPhone <span style="color:#008000;">=</span> host<span style="color:#008000;">.</span><span style="color:#0000ff;">GetRestaurantPhoneNumber</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//clean the place:</span>
		host<span style="color:#008000;">.</span><span style="color:#0000ff;">CleanUpPlace</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//set up furniture</span>
		host<span style="color:#008000;">.</span><span style="color:#0000ff;">SetupFurniture</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//call food chef into your apartment to prepare food</span>
		<span style="font-style:italic;color:#008080;">//the chef will come and will make the food at your place</span>
		<span style="color:#6666cc;font-weight:bold;">string</span> getFood <span style="color:#008000;">=</span> restaurantPhone<span style="color:#008000;">.</span><span style="color:#0000ff;">Invoke</span><span style="color:#008000;">(</span><span style="color:#666666;">"sushi"</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//register when food is done:</span>
		Console<span style="color:#008000;">.</span><span style="color:#0000ff;">WriteLine</span><span style="color:#008000;">(</span>getFood <span style="color:#008000;">+</span> <span style="color:#666666;">" at "</span> <span style="color:#008000;">+</span> DateTime<span style="color:#008000;">.</span><span style="color:#0000ff;">Now</span><span style="color:#008000;">.</span><span style="color:#0000ff;">ToLongTimeString</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//prepare yourself:</span>
		host<span style="color:#008000;">.</span><span style="color:#0000ff;">TakeBathAndDressUp</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//mark end time:</span>
		<span style="color:#6666cc;font-weight:bold;">long</span> end <span style="color:#008000;">=</span> DateTime<span style="color:#008000;">.</span><span style="color:#0000ff;">Now</span><span style="color:#008000;">.</span><span style="color:#0000ff;">Ticks</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//register total time:</span>
		Console<span style="color:#008000;">.</span><span style="color:#0000ff;">WriteLine</span><span style="color:#008000;">(</span><span style="color:#666666;">"Total time {0} seconds"</span>, <span style="color:#008000;">(</span>end <span style="color:#008000;">-</span> start<span style="color:#008000;">)</span> <span style="color:#008000;">/</span> <span style="color:#ff0000;">10000000</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   Console<span style="color:#008000;">.</span><span style="color:#0000ff;">Read</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>
	<span style="color:#008000;">}</span>
<span style="color:#008000;">}</span>

Hình ảnh dưới đây mô tả quá trình đoạn chương trình trên:

Khi bạn sử dụng lời gọi hàm đồng thời (synchronous call), bạn ra lệnh cho compiler thực thi hàm mà delegate trỏ tới ngay trên thread của hàm Main. Nó tương tự như việc tôi mời một đầu bếp tới nhà tôi để làm đồ ăn vậy. Mọi công việc diễn ra theo một trình tự. Công việc tiếp theo chỉ được thực hiện sau khi công việc trước đó kết thúc. Ở đây, chương trình mất 11s để hoàn thành công việc.

Trường hợp thứ hai đó là ta sẽ thực hiện asynchronous call. Thay vì gọi phương thức Invoke, chương trình sẽ gọi phương thức BeginInvoke. Có một chút khác biệt trong việc gọi hàm:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
IAsyncResult asyncResult <span style="color:#008000;">=</span> restaurantPhone<span style="color:#008000;">.</span><span style="color:#0000ff;">BeginInvoke</span><span style="color:#008000;">(</span><span style="color:#666666;">"sushi"</span>, <span style="color:#0600ff;font-weight:bold;">null</span>, <span style="color:#0600ff;font-weight:bold;">null</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span> 
<span style="color:#0600ff;font-weight:bold;">public</span> <span style="color:#6666cc;font-weight:bold;">class</span> AsyncNoCallBackBadTiming
<span style="color:#008000;">{</span>
	<span style="font-style:italic;color:#008080;">/// <summary></span>
	<span style="font-style:italic;color:#008080;">/// Invoking Async No Call Back Bad Timing</span>
	<span style="font-style:italic;color:#008080;">/// </summary></span>
	<span style="font-style:italic;color:#008080;">/// <param name="args"></span>
	<span style="color:#0600ff;font-weight:bold;">static</span> <span style="color:#6666cc;font-weight:bold;">void</span> Main<span style="color:#008000;">(</span><span style="color:#6666cc;font-weight:bold;">string</span><span style="color:#008000;">[</span><span style="color:#008000;">]</span> args<span style="color:#008000;">)</span>
	<span style="color:#008000;">{</span>
		<span style="font-style:italic;color:#008080;">//mark start:</span>
		<span style="color:#6666cc;font-weight:bold;">long</span> start <span style="color:#008000;">=</span> DateTime<span style="color:#008000;">.</span><span style="color:#0000ff;">Now</span><span style="color:#008000;">.</span><span style="color:#0000ff;">Ticks</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//initialize host:</span>
		PartyHost host <span style="color:#008000;">=</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="color:#008000;">new</span></a> PartyHost<span style="color:#008000;">(</span><span style="color:#666666;">"Ed"</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//find a restaurant phone number in phone book;</span>
		<span style="font-style:italic;color:#008080;">//it is your delegate:</span>
		OrderHandle restaurantPhone <span style="color:#008000;">=</span> host<span style="color:#008000;">.</span><span style="color:#0000ff;">GetRestaurantPhoneNumber</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//clean up:</span>
		host<span style="color:#008000;">.</span><span style="color:#0000ff;">CleanUpPlace</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//set furniture:</span>
		host<span style="color:#008000;">.</span><span style="color:#0000ff;">SetupFurniture</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//call the restaurant to order food and get a token </span>
		<span style="font-style:italic;color:#008080;">//from them identifying </span>
		<span style="font-style:italic;color:#008080;">//your order. they immediately start preparing food:</span>
		IAsyncResult asyncResult <span style="color:#008000;">=</span> restaurantPhone<span style="color:#008000;">.</span><span style="color:#0000ff;">BeginInvoke</span>
					<span style="color:#008000;">(</span><span style="color:#666666;">"sushi"</span>, <span style="color:#0600ff;font-weight:bold;">null</span>, <span style="color:#0600ff;font-weight:bold;">null</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="color:#6666cc;font-weight:bold;">string</span> getFood<span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//call the restaurant, provide the token, get the food, </span>
		<span style="font-style:italic;color:#008080;">//don't be surprised that</span>
		<span style="font-style:italic;color:#008080;">//you have to wait until the food is ready.</span>
		getFood <span style="color:#008000;">=</span> restaurantPhone<span style="color:#008000;">.</span><span style="color:#0000ff;">EndInvoke</span><span style="color:#008000;">(</span>asyncResult<span style="color:#008000;">)</span><span style="color:#008000;">;</span>   Console<span style="color:#008000;">.</span><span style="color:#0000ff;">WriteLine</span><span style="color:#008000;">(</span>getFood <span style="color:#008000;">+</span> <span style="color:#666666;">" at "</span> <span style="color:#008000;">+</span> DateTime<span style="color:#008000;">.</span><span style="color:#0000ff;">Now</span><span style="color:#008000;">.</span><span style="color:#0000ff;">ToLongTimeString</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//take care of yourself:</span>
		host<span style="color:#008000;">.</span><span style="color:#0000ff;">TakeBathAndDressUp</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//mark the end:</span>
		<span style="color:#6666cc;font-weight:bold;">long</span> end <span style="color:#008000;">=</span> DateTime<span style="color:#008000;">.</span><span style="color:#0000ff;">Now</span><span style="color:#008000;">.</span><span style="color:#0000ff;">Ticks</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//register total time:</span>
		Console<span style="color:#008000;">.</span><span style="color:#0000ff;">WriteLine</span><span style="color:#008000;">(</span><span style="color:#666666;">"Total time {0} seconds"</span>, <span style="color:#008000;">(</span>end <span style="color:#008000;">-</span> start<span style="color:#008000;">)</span> <span style="color:#008000;">/</span> <span style="color:#ff0000;">10000000</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   Console<span style="color:#008000;">.</span><span style="color:#0000ff;">Read</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>
	<span style="color:#008000;">}</span>
<span style="color:#008000;">}</span>

Hình ảnh dưới đây sẽ thể hiện những gì diễn ra trong đoạn chương trình trên:

Khi sử dụng asynchronous call, bạn ra lệnh cho compiler lấy một thread từ thread pool (hoặc tạo một thread mới). Thay vì chuẩn bị thức ăn tại nhà tôi, tôi yêu cầu nhà hàng làm thức ăn tại chỗ của họ, sau đó mang đến cho tôi. Công việc lúc này được thực hiện ở một nơi khác. Và nhờ đó, main thread không cần phải chờ cho đến khi function hoàn thành. Nó có thể tiếp túc thực hiện các chức năng khác.

Tuy nhiên, ở đây tôi lại gọi phương thức EndInvoke ngay sau khi gọi phương thức BeginInvoke. Vì vậy, main thread sẽ đợi cho đến khi EndInvoke hoàn thành. Phương thức này chỉ kết thúc khi function MakeFood kết thúc. Việc này sẽ block main thread lại và tất cả những lợi ích của việc sử dụng asynchronous call trở nên vô nghĩa. Thời gian tổng cộng vẫn là 11 giây.

Trong trường hợp thứ 3, tôi sẽ sửa lại lỗi này. Bây giờ, tôi sẽ order trước. Trong khi thức ăn được chuẩn bị, tôi có thể làm một vài việc khác, ví dụ như dọn nhà, kê bàn ghế… Như vậy, phương thức BeginInvoke được gọi, main thread lúc này quay trở lại thực thi tiếp công việc của nó. Cho đến khi phương thức EndInvoke được gọi tức là thức ăn đã sẵn sàng. Bây giờ, tổng thời gian chỉ là 7s:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<span style="color:#0600ff;font-weight:bold;">public</span> <span style="color:#6666cc;font-weight:bold;">class</span> AsyncNoCallBackGoodTiming
<span style="color:#008000;">{</span>
    <span style="font-style:italic;color:#008080;">/// <summary></span>
	<span style="font-style:italic;color:#008080;">/// Invoking Async No Call Back Good Timing</span>
	<span style="font-style:italic;color:#008080;">/// </summary></span>
	<span style="font-style:italic;color:#008080;">/// <param name="args"></span>
	<span style="color:#0600ff;font-weight:bold;">static</span> <span style="color:#6666cc;font-weight:bold;">void</span> Main<span style="color:#008000;">(</span><span style="color:#6666cc;font-weight:bold;">string</span><span style="color:#008000;">[</span><span style="color:#008000;">]</span> args<span style="color:#008000;">)</span>
	<span style="color:#008000;">{</span>
		<span style="font-style:italic;color:#008080;">//mark start:</span>
		<span style="color:#6666cc;font-weight:bold;">long</span> start <span style="color:#008000;">=</span> DateTime<span style="color:#008000;">.</span><span style="color:#0000ff;">Now</span><span style="color:#008000;">.</span><span style="color:#0000ff;">Ticks</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//initialize host:</span>
		PartyHost host <span style="color:#008000;">=</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="color:#008000;">new</span></a> PartyHost<span style="color:#008000;">(</span><span style="color:#666666;">"Ed"</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//find a restaurant phone number in phone book;</span>
		<span style="font-style:italic;color:#008080;">//it is your delegate:</span>
		OrderHandle restaurantPhone <span style="color:#008000;">=</span> host<span style="color:#008000;">.</span><span style="color:#0000ff;">GetRestaurantPhoneNumber</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//call the restaurant to order food and get a token from them </span>
		<span style="font-style:italic;color:#008080;">//identifying your order. they immediately start preparing food:</span>
		IAsyncResult asyncResult <span style="color:#008000;">=</span> restaurantPhone<span style="color:#008000;">.</span><span style="color:#0000ff;">BeginInvoke</span>
					<span style="color:#008000;">(</span><span style="color:#666666;">"sushi"</span>, <span style="color:#0600ff;font-weight:bold;">null</span>, <span style="color:#0600ff;font-weight:bold;">null</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//clean up:</span>
		host<span style="color:#008000;">.</span><span style="color:#0000ff;">CleanUpPlace</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//set furniture:</span>
		host<span style="color:#008000;">.</span><span style="color:#0000ff;">SetupFurniture</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="color:#6666cc;font-weight:bold;">string</span> getFood<span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//call the restaurant, provide the token, get the food</span>
		getFood <span style="color:#008000;">=</span> restaurantPhone<span style="color:#008000;">.</span><span style="color:#0000ff;">EndInvoke</span><span style="color:#008000;">(</span>asyncResult<span style="color:#008000;">)</span><span style="color:#008000;">;</span>   Console<span style="color:#008000;">.</span><span style="color:#0000ff;">WriteLine</span><span style="color:#008000;">(</span>getFood <span style="color:#008000;">+</span> <span style="color:#666666;">" at "</span> <span style="color:#008000;">+</span> DateTime<span style="color:#008000;">.</span><span style="color:#0000ff;">Now</span><span style="color:#008000;">.</span><span style="color:#0000ff;">ToLongTimeString</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//take care of yourself:</span>
		host<span style="color:#008000;">.</span><span style="color:#0000ff;">TakeBathAndDressUp</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//mark the end:</span>
		<span style="color:#6666cc;font-weight:bold;">long</span> end <span style="color:#008000;">=</span> DateTime<span style="color:#008000;">.</span><span style="color:#0000ff;">Now</span><span style="color:#008000;">.</span><span style="color:#0000ff;">Ticks</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//register total time:</span>
		Console<span style="color:#008000;">.</span><span style="color:#0000ff;">WriteLine</span><span style="color:#008000;">(</span><span style="color:#666666;">"Total time {0} seconds"</span>, <span style="color:#008000;">(</span>end <span style="color:#008000;">-</span> start<span style="color:#008000;">)</span> <span style="color:#008000;">/</span> <span style="color:#ff0000;">10000000</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   Console<span style="color:#008000;">.</span><span style="color:#0000ff;">Read</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>
	<span style="color:#008000;">}</span>
<span style="color:#008000;">}</span>

Đây là hình ảnh mô tả quá trình diễn ra trong đoạn chương trình trên:

Trường hợp cuối cùng sẽ giải thích cho bạn cách sử dụng CallBack function. Như tôi đã đề cập từ trước, phương thức BeginInvoke có thêm 2 tham số phía sau mà trong các trường hợp trên chúng ta chưa dùng tới. Đầu tiên đó là delegate CallBackFunction. Ở đây tôi sử dụng một static function:

1
<span style="color:#0600ff;font-weight:bold;">private</span> <span style="color:#0600ff;font-weight:bold;">static</span> <span style="color:#6666cc;font-weight:bold;">void</span> FoodDeliveryNotification<span style="color:#008000;">(</span>IAsyncResult result<span style="color:#008000;">)</span><span style="color:#008000;">{ </span><span style="color:#008000;">}</span>

Phương thức này nhận tham số có kiểu IAsyncResult và return void. Bởi vì tham số truyền vào phương thức BeginInvoke là một delegate, do đó tôi sử dụng từ khóa new để tạo một thể hiện mới cho delegate, đồng thời trỏ delegate này tới phương thức FoodDeliveryNotification:

1
2
restaurantPhone<span style="color:#008000;">.</span><span style="color:#0000ff;">BeginInvoke</span><span style="color:#008000;">(</span><span style="color:#666666;">"sushi"</span>, 
	<a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="color:#008000;">new</span></a> AsyncCallback<span style="color:#008000;">(</span>FoodDeliveryNotification<span style="color:#008000;">)</span>, restaurantPhone<span style="color:#008000;">)</span><span style="color:#008000;">;</span>  

Tham số thứ hai trong phương thức BeginInvoke là một object và tôi có thể truyền bất kì object nào mà tôi muốn vào đây. Trong trường hợp này, tôi gọi lại chính delegate restaurantPhone. Như chúng ta đã biết, phương thức MakeFood được thực thi trên một thread khác. Khi function này kết thúc, nó sẽ kích hoạt hàm callback FoodDeliveryNotification. Một vài công viecj sẽ được thực thi bên trong hàm này:

  1. Nhận việc gọi delegate

  2. Gọi phương thức EndInvoke và truyền tham số IasyncResult vào.

  3. Xử lí kết quả trả về.

Trong trường hợp này, đoạn chương trình bên trong hàm main không trực tiếp gọi phương thức EndInvoke.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<span style="color:#0600ff;font-weight:bold;">public</span> <span style="color:#6666cc;font-weight:bold;">class</span> AsyncCallBack
<span style="color:#008000;">{</span>
        <span style="font-style:italic;color:#008080;">/// <summary></span>
	<span style="font-style:italic;color:#008080;">/// Invoking Async Call Back</span>
	<span style="font-style:italic;color:#008080;">/// </summary></span>
	<span style="font-style:italic;color:#008080;">/// <param name="args"></span>
	<span style="color:#0600ff;font-weight:bold;">static</span> <span style="color:#6666cc;font-weight:bold;">void</span> Main<span style="color:#008000;">(</span><span style="color:#6666cc;font-weight:bold;">string</span><span style="color:#008000;">[</span><span style="color:#008000;">]</span> args<span style="color:#008000;">)</span>
	<span style="color:#008000;">{</span>
		<span style="font-style:italic;color:#008080;">//mark start:</span>
		<span style="color:#6666cc;font-weight:bold;">long</span> start <span style="color:#008000;">=</span> DateTime<span style="color:#008000;">.</span><span style="color:#0000ff;">Now</span><span style="color:#008000;">.</span><span style="color:#0000ff;">Ticks</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//initialize host:</span>
		PartyHost host <span style="color:#008000;">=</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="color:#008000;">new</span></a> PartyHost<span style="color:#008000;">(</span><span style="color:#666666;">"Ed"</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//find a restaurant phone number in phone book;</span>
		<span style="font-style:italic;color:#008080;">//it is your delegate:</span>
		OrderHandle restaurantPhone <span style="color:#008000;">=</span> host<span style="color:#008000;">.</span><span style="color:#0000ff;">GetRestaurantPhoneNumber</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//call the restaurant to order food and get a token </span>
		<span style="font-style:italic;color:#008080;">//from them identifying your order. </span>
		<span style="font-style:italic;color:#008080;">//They immediately start preparing food:</span>
		restaurantPhone<span style="color:#008000;">.</span><span style="color:#0000ff;">BeginInvoke</span><span style="color:#008000;">(</span><span style="color:#666666;">"sushi"</span>, <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="color:#008000;">new</span></a> AsyncCallback
			<span style="color:#008000;">(</span>FoodDeliveryNotification<span style="color:#008000;">)</span>, restaurantPhone<span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//clean up:</span>
		host<span style="color:#008000;">.</span><span style="color:#0000ff;">CleanUpPlace</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//set furniture:</span>
		host<span style="color:#008000;">.</span><span style="color:#0000ff;">SetupFurniture</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//take care of yourself:</span>
		host<span style="color:#008000;">.</span><span style="color:#0000ff;">TakeBathAndDressUp</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//mark the end:</span>
		<span style="color:#6666cc;font-weight:bold;">long</span> end <span style="color:#008000;">=</span> DateTime<span style="color:#008000;">.</span><span style="color:#0000ff;">Now</span><span style="color:#008000;">.</span><span style="color:#0000ff;">Ticks</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//register total time:</span>
		Console<span style="color:#008000;">.</span><span style="color:#0000ff;">WriteLine</span><span style="color:#008000;">(</span><span style="color:#666666;">"Total time {0} seconds"</span>, <span style="color:#008000;">(</span>end <span style="color:#008000;">-</span> start<span style="color:#008000;">)</span> <span style="color:#008000;">/</span> <span style="color:#ff0000;">10000000</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>   Console<span style="color:#008000;">.</span><span style="color:#0000ff;">Read</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>
	<span style="color:#008000;">}</span>   <span style="color:#0600ff;font-weight:bold;">private</span> <span style="color:#0600ff;font-weight:bold;">static</span> <span style="color:#6666cc;font-weight:bold;">void</span> FoodDeliveryNotification<span style="color:#008000;">(</span>IAsyncResult result<span style="color:#008000;">)</span>
	<span style="color:#008000;">{</span>
		<span style="font-style:italic;color:#008080;">//get the delegate:</span>
		OrderHandle handle <span style="color:#008000;">=</span> <span style="color:#008000;">(</span>OrderHandle<span style="color:#008000;">)</span>result<span style="color:#008000;">.</span><span style="color:#0000ff;">AsyncState</span><span style="color:#008000;">;</span>   <span style="font-style:italic;color:#008080;">//call end invoke:</span>
		<span style="color:#6666cc;font-weight:bold;">string</span> getFood <span style="color:#008000;">=</span> handle<span style="color:#008000;">.</span><span style="color:#0000ff;">EndInvoke</span><span style="color:#008000;">(</span>result<span style="color:#008000;">)</span><span style="color:#008000;">;</span>   Console<span style="color:#008000;">.</span><span style="color:#0000ff;">WriteLine</span><span style="color:#008000;">(</span>getFood <span style="color:#008000;">+</span> <span style="color:#666666;">" at "</span> <span style="color:#008000;">+</span> DateTime<span style="color:#008000;">.</span><span style="color:#0000ff;">Now</span><span style="color:#008000;">.</span><span style="color:#0000ff;">ToLongTimeString</span><span style="color:#008000;">(</span><span style="color:#008000;">)</span><span style="color:#008000;">)</span><span style="color:#008000;">;</span>
	<span style="color:#008000;">}</span>
<span style="color:#008000;">}</span>
<span style="color:#008000;">}</span>

Summary

Ở bài viết này, bạn đã biết cách gọi một delegate không cùng lúc. Mặc dù bạn biết cách sử dụng nhưng bạn cũng không cần thiết phải sử dụng nó. Thông thường, nó hay được sử dụng khi delegate call một chức năng I/O nào đó. Tuy nhiên, dựa vào những đánh giá về cách đặt các lời gọi hàm trong chương trình của bạn để có thể sử dụng chức năng này đúng đắn. Nếu sử dụng không đúng, bạn có thể làm chậm chương trình của mình và tất nhiên nó sẽ chẳng mang lại lợi ích nào cả.

Nguyên bản: http://www.codeproject.com/KB/cs/delegatespart2.aspx

This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.