Thứ Bảy, 14 tháng 4, 2012

Bàn về Generic Class và Generic Delegate



1 - Generic là gì?
-- Hiểu nôm na, đơn giản generic cũng là một kiểu dữ liệu trong C#, nó cũng như là int, float, string, bool.... nhưng điểm khác biệt ở đây generic nó là một kiểu dữ liệu "tự do", mình nói tự do có nghĩa là nó có thể là kiểu dữ liệu nào cũng được, tùy vào mục đích sử dụng của mình, nó như là 1 kiểu đại diện cho tất cả các kiểu dữ liệu còn lại vậy : . Hơi khó hiểu nhưng hãy xem tiếp những phần dưới thì sẽ dễ hiểu hơn ^^


2 - Generic Class:
-- Đặt vấn đề: Bây giờ mình cần xây dựng 1 class myClass, trong đó có 2 hàm khởi dựng:
-- Hàm đầu tiên: Thông số truyền vào là kiểu Int => Xuất ra kiểu dữ liệu của tham số truyền vào và giá trị của tham số đó.
-- Hàm thứ hai: Thông số truyền vào là kiểu string => Xuất ra kiểu dữ liệu của tham số truyền vào và giá trị của tham số đó.

Quá đơn giản đúng ko , như vậy ta có đoạn code sau:
PHP:

   
public class myClass
   
{
        
//Ham khoi dung 1
        
public myClass(int myInt)
        {                               
            
Console.WriteLine("My Type is: " myInt.GetType());
            
Console.WriteLine("My value is: " myInt.ToString());
        }
        
//Ham khoi dung 2
        
public myClass(string myStr)
        {
            
Console.WriteLine("My Type is: " myStr.GetType());
            
Console.WriteLine("My value is: " myStr.ToString());
        }
    }
    class 
MainClass
    
{
        public static 
void Main()
        {        
            
myClass myclass1 = new myClass(5);
            
myClass myclass2 = new myClass("Hello");
            
Console.ReadKey();
        }
    }
Kết quả xuất ra sẽ là:



Như vậy nếu yêu cầu đặt ra không phải là 2 hàm khởi dựng mà là 5 hay 10 hay 100 thì sao nhỉ? Không lẽ phải đi viết 100 hàm khởi dựng cho mỗi kiểu dữ liệu 
Giải pháp đưa ra sẽ là Generic Class ^^
Cú pháp khai báo một Generic Class: [attributes] class_name<T>{}
Đơn giản chỉ vậy ^^
Bây giờ các bạn xem đoạn code sau:

PHP:

    
public class myClass<T>
    {
        
T mytype;
        public 
myClass(T myType)
        {
            
this.mytype myType;
            
Console.WriteLine("My Type is: " typeof(T));
        }
        
//Lay gia tri cua tham so truyen vao
        
public T getValue()
        {
            return 
this.mytype;
        }   
    }
    class 
MainClass
    
{
        public static 
void Main()
        {
            
myClass<intmyclass1 = new myClass<int>(100);
            
int nInt myclass1.getValue();
            
Console.WriteLine("My value is: {0}"nInt);

            
myClass<stringmyclass2 = new myClass<string>("Hello moto ^^");
            
string myString myclass2.getValue();
            
Console.WriteLine("My value is: {0}"myString);
            
Console.ReadKey();
        }
    }
Kết quả:








Ta thấy bây giờ đoạn code của myClass gọn hơn rất nhiều nhờ Generic, chỉ 1 đoạn code ngắn như vậy nhưng có phạm vi sử dụng rất lớn, tức là có thể gọi đựoc rất nhiều hàm khởi dựng như vấn đề đặt ra :))

Ví dụ bây giờ ta mún gọi một hàm khởi dựng mà tham số truyền vào là bool thì sao? Rất đơn giản là trong hàm Main bạn chỉ cần gọi như sau:

PHP:

            myClass
<boolmyclass3 = new myClass<bool>(true);
            
bool myBool myclass3.getValue();
            
Console.WriteLine("My value is: {0}"myBool);
 ta ko cần phải can thiệp vào class chính ^^

Ngoài ra C# còn cho phép chúng ta sử dụng Generic Class với 2 tham số truyền vào đó là T và V. Cú pháp khai báo như sau:

PHP:
class myClass2<TV> {}
Phần thân thì xử lý tương tự 

2 -- Generic Delegate:

-- Như đã biết, bản chất của Delegate là nó chỉ có thể gọi tới những hàm có cùng kiểu trả về và cùng kiểu dữ liệu của tham số truyền vào hàm được ủy thác. 
-- Như vậy vấn đề đặt ra là làm cách nào để 1 hàm ủy thác duy nhất có thể gọi tới nhiều hàm khác nhau có kiểu dữ liệu của tham số truyền vào khác nhau , rườm rà quá, đi vào ví dụ cụ thể luôn nhá :d
-- Xây dựng 1 hàm ủy thác có khả năng gọi tới 2 hàm có 2 chức năng khác nhau đó là:
-- Hàm 1: Tham số truyền vào là một chuỗi, hàm sẽ xuất ra chuỗi truyền vào dưới dạng IN HOA.
-- Hàm 2: Tham số truyền vào là số nguyên, hàm sẽ xuất ra giá trị của tham số truyền vào nhân 10.
--> Nếu cố ý đọc NHẦM đề thì ta có thể xây dựng hàm ủy thác như sau: 

PHP:

/*Khai báo hàm ủy thác
 * Kiểu dữ liệu truyền vào là tùy ý
 */
public delegate void MyDelegate(object arg);
class 
Program{
    static 
void MyTarget(object arg)
    {
        if (
arg is int)//Nếu tham số truyền vào là Int
        
{
            
int i = (int)arg;
            
Console.WriteLine("arg*10 is: {0}"i*10);
        }

        if (
arg is string)//Nếu tham số truyền vào là string
        
{
            
string s = (string)arg;
            
Console.WriteLine("arg in uppercase is: {0}"s.ToUpper());
        }
    }
    static 
void Main(string[] args)
    {
        
MyDelegate d = new MyDelegate(MyTarget);
        
d("string");
        
MyDelegate d2 = new MyDelegate(MyTarget);
        
d2(10);
        
Console.ReadKey();
    }
}
Kết quả xuất ra:



Xem ra cũng có vẻ hợp lý khi nhìn vào kết quả xuất ra nhỉ :d
Nhưng rõ ràng làm như vậy là không thực tế cho lắm so với yêu cầu đưa ra. Như vậy thì phải làm sao trong khi bản chất của Delegate là chỉ gọi được những hàm có cùng số lượng tham số và cùng kiểu dữ liệu 
-- Giải pháp đưa ra là: Dĩ nhiên là Generic Delegate roài (Đang PR cho em nó mà:)
-- Cú pháp khai báo một Generic Delegate: [attributes] delegate returntype delegate_name<T>(T [parameters])
Như vậy với yêu cầu trên ta có đoạn code sau :d :

PHP:

public delegate void MyGenericDelegate<T>(T arg);
class 
Program{
    
//2 ham duoc uy thac
    
static void StringTarget(string arg)// Ham 1 voi tham so truyen vao kieu string
    
{
        
Console.WriteLine("arg in uppercase is: {0}"arg.ToUpper());
    }
    
// Ham 1 voi tham so truyen vao kieu int
    
static void IntTarget(int arg)
    {
        
Console.WriteLine("arg*10 is: {0}"arg*10);
    }
    static 
void Main(string[] args)
    {    
        
// Khai bao ham uy thac voi thong so truyen vao kieu string
        
MyGenericDelegate<stringstrTarget = new MyGenericDelegate<string>(StringTarget);
        
strTarget("my string");

        
// Khai bao ham uy thac voi thong so truyen vao kieu int
        
MyGenericDelegate<intintTarget IntTarget;
        
intTarget(10);
        
Console.ReadKey();
    }
}
Kết quả: 



Như vậy ta thấy, nhờ có Generic mà chỉ với 1 hàm ủy thác duy nhất chúng ta có thể gọi tới 2 hàm có 2 kiểu dữ liệu của tham số truyền vào hoàn toàn khác nhau 
Đoạn code trên quá rõ ràng rùi đúng hem :d, chắc ko cần phải giải thích thêm làm gì đâu nhỉ 

Giờ mình chơi sang hơn 1 tí, ở ví dụ trên các hàm được gọi tới từ hàm ủy thác đề trả về cùng kiểu là void, giờ sang hơn là muốn trả về gì cũng được nhưng hạn chế ở đây là kiểu trả vè của hàm và tham số truyền vào phải giống nhau ^^

PHP:

//Khai bao ham uy thac tra ve kieu tu dodelegate T MyDelegate<T>(T v);
class 
MainClass{
    
//Ham 1 tra ve int và tham so truyen vao cung int
    
static int sum(int v)
    {
        return 
v;
    }
    
//Ham 2 tra ve string và tham so truyen vao cung string
    
static string reflect(string str)
    {
        return 
str;
    }
    public static 
void Main()
    {
        
MyDelegate<intintDel sum;
        
Console.WriteLine(intDel(100));

        
MyDelegate<stringstrDel reflect;
        
Console.WriteLine(strDel("Hello Ajinomoto ^^"));
        
Console.ReadKey();
    }
}
Kết quả:



theo: tamnhinso.info
Share this post
  • Share to Facebook
  • Share to Twitter
  • Share to Google+
  • Share to Stumble Upon
  • Share to Evernote
  • Share to Blogger
  • Share to Email
  • Share to Yahoo Messenger
  • More...

0 nhận xét

:) :-) :)) =)) :( :-( :(( :d :-d @-) :p :o :>) (o) [-( :-? (p) :-s (m) 8-) :-t :-b b-( :-# =p~ :-$ (b) (f) x-) (k) (h) (c) cheer

 
© Download do an khoa luan tai lieu
Designed by BlogThietKe Cooperated with Duy Pham
Released under Creative Commons 3.0 CC BY-NC 3.0
Posts RSSComments RSS
Back to top