Hướng dẫn và ví dụ C# Generics
1. Lớp Generics
Ví dụ dưới đây định nghĩa ra một lớp generics. KeyValue là một lớp generics nó chứa một cặp khóa và giá trị (key/value).
KeyValue.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GenericsTutorial
{
public class KeyValue<K, V>
{
private K key;
private V value;
public KeyValue(K key, V value)
{
this.key = key;
this.value = value;
}
public K GetKey()
{
return key;
}
public void SetKey(K key)
{
this.key = key;
}
public V GetValue()
{
return value;
}
public void SetValue(V value)
{
this.value = value;
}
}
}
K, V trong lớp KeyValue<K,V> được gọi là tham số generics nó là một kiểu dữ liệu nào đó. Khi sử dụng lớp này bạn phải xác định kiểu tham số cụ thể.
Hãy xem ví dụ sử dụng lớp KeyValue.
KeyValueDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GenericsTutorial
{
public class KeyValueDemo
{
public static void Main(string[] args)
{
// Tạo một đối tượng KeyValue.
// int: Số điện thoại (K = int)
// string: Tên người dùng. (V = string).
KeyValue<int, string> entry = new KeyValue<int, string>(12000111, "Tom");
// C# hiểu kiểu trả về là int (K = int).
int phone = entry.GetKey();
// C# hiểu kiểu trả về là string (V = string).
string name = entry.GetValue();
Console.WriteLine("Phone = " + phone + " / name = " + name);
Console.Read();
}
}
}
Chạy ví dụ:
Phone = 12000111 / name = Tom
2. Thừa kế lớp Generics
Một lớp mở rộng từ một lớp generics, nó có thể chỉ định rõ kiểu cho tham số generics, giữ nguyên các tham số generics hoặc thêm các tham số generics.
Ví dụ 1:
PhoneNameEntry.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GenericsTutorial
{
// Lớp này mở rộng từ lớp KeyValue<K,V>
// Và chỉ định rõ kiểu cho 2 tham số K & V
// K = int (Số điện thoại).
// V = string (Tên người dùng).
public class PhoneNameEntry : KeyValue<int, string>
{
public PhoneNameEntry(int key, string value)
: base(key, value)
{
}
}
}
Ví dụ sử dụng PhoneNameEntry:
PhoneNameEntryDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GenericsTutorial
{
public class PhoneNameEntryDemo
{
public static void Main(string[] args)
{
PhoneNameEntry entry = new PhoneNameEntry(12000111, "Tom");
// C# hiểu rằng kiểu trả về này là int.
int phone = entry.GetKey();
// C# hiểu kiểu trả về này là string.
string name = entry.GetValue();
Console.WriteLine("Phone = " + phone + " / name = " + name);
Console.Read();
}
}
}
Ví dụ 2:
StringAndValueEntry.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GenericsTutorial
{
// Lớp này mở rộng từ lớp KeyValue<K,V>
// Xác định rõ kiểu tham số K là String.
// Giữ nguyên kiểu tham số generic V.
public class StringAndValueEntry<V> : KeyValue<string, V>
{
public StringAndValueEntry(string key, V value)
: base(key, value)
{
}
}
}
Ví dụ sử dụng lớp StringAndValueEntry:
StringAndValueEntryDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GenericsTutorial
{
public class StringAndValueEntryDemo
{
public static void main(String[] args)
{
// (Mã nhân viên, Tên nhân viên).
// V = string (Tên nhân viên)
StringAndValueEntry<String> entry = new StringAndValueEntry<String>("E001", "Tom");
String empNumber = entry.GetKey();
String empName = entry.GetValue();
Console.WriteLine("Emp Number = " + empNumber);
Console.WriteLine("Emp Name = " + empName);
Console.Read();
}
}
}
Ví dụ 3:
KeyValueInfo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GenericsTutorial
{
// Lớp này mở rộng từ lớp KeyValue<K,V>.
// Nó có thêm một tham số Generics I.
public class KeyValueInfo<K, V, I> : KeyValue<K, V>
{
private I info;
public KeyValueInfo(K key, V value)
: base(key, value)
{
}
public KeyValueInfo(K key, V value, I info)
: base(key, value)
{
this.info = info;
}
public I GetInfo()
{
return info;
}
public void GetInfo(I info)
{
this.info = info;
}
}
}
3. Interface Generics
Một Interface có tham số Generics:
GenericInterface.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GenericsTutorial
{
public interface GenericInterface<G>
{
G DoSomething();
}
}
Ví dụ một lớp thực hiện (implements) Interface:
GenericInterfaceImpl.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GenericsTutorial
{
public class GenericInterfaceImpl<G> : GenericInterface<G>
{
private G something;
public G DoSomething()
{
return something;
}
}
}
4. Sử dụng Generic với Exception
Bạn có thể định nghĩa một Exception có các tham số Generics.
MyException.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GenericsTutorial
{
class MyException<E> : ApplicationException
{
}
}
Sử dụng Generic Exception hợp lệ:
UsingGenericExceptionValid01.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GenericsTutorial
{
class UsingGenericExceptionValid01
{
public void SomeMethod()
{
try
{
// ...
}
// Hợp lệ
catch (MyException<string> e)
{
// Làm gì đó ở đây.
}
// Hợp lệ
catch (MyException<int> e)
{
// Làm gì đó ở đây.
}
catch (Exception e)
{
}
}
}
}
Sử dụng Generics Exception hợp lệ:
UsingGenericExceptionValid02.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GenericsTutorial
{
class UsingGenericExceptionValid02<K>
{
public void SomeMethod()
{
try
{
// ...
}
// Hợp lệ
catch (MyException<string> e)
{
// Làm gì đó ở đây.
}
// Hợp lệ
catch (MyException<K> e)
{
// Làm gì đó ở đây.
}
catch (Exception e)
{
}
}
}
}
Sử dụng Generics Exception không hợp lệ:
UsingGenericExceptionInvalid.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GenericsTutorial
{
class UsingGenericExceptionInvalid
{
public void SomeMethod()
{
try
{
// ...
}
// Hợp lệ
catch (MyException<string> e)
{
// Làm gì đó ở đây.
}
// Invalid (Unknown parameter K) ***********
// catch (MyException<K> e)
// {
// ...
// }
catch (Exception e)
{
}
}
}
}
5. Phương thức generics
Một phương thức trong lớp hoặc Interface có thể được Generic hóa (generify).
MyUtils.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GenericsTutorial
{
public class MyUtils
{
// <K,V> : Nói rằng phương thức này có 2 kiểu tham số K,V
// Phương thức trả về kiểu K.
public static K GetKey<K, V>(KeyValue<K, V> entry)
{
K key = entry.GetKey();
return key;
}
// <K,V> : Nói rằng phương thức này có 2 kiểu tham số K,V
// Phương thức trả về kiểu V.
public static V GetValue<K, V>(KeyValue<K, V> entry)
{
V value = entry.GetValue();
return value;
}
// List<E>: Danh sách chứa các phần tử kiểu E
// Phương thức này trả về kiểu E.
public static E GetFirstElement<E>(List<E> list, E defaultValue)
{
if (list == null || list.Count == 0)
{
return defaultValue;
}
E first = list.ElementAt(0);
return first;
}
}
}
Ví dụ sử dụng phương thức generics:
MyUtilsDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GenericsTutorial
{
public class MyUtilsDemo
{
public static void Main(string[] args)
{
// K = int: Phone
// V = string: Name
KeyValue<int, string> entry1 = new KeyValue<int, String>(12000111, "Tom");
KeyValue<int, string> entry2 = new KeyValue<int, String>(12000112, "Jerry");
// (K = int).
int phone = MyUtils.GetKey(entry1);
Console.WriteLine("Phone = " + phone);
// Một danh sách chứa các phần tử kiểu KeyValue<int,string>.
List<KeyValue<int, string>> list = new List<KeyValue<int, string>>();
// Thêm phần tử vào danh sách.
list.Add(entry1);
list.Add(entry2);
KeyValue<int, string> firstEntry = MyUtils.GetFirstElement(list, null);
if (firstEntry != null)
{
Console.WriteLine("Value = " + firstEntry.GetValue());
}
Console.Read();
}
}
}
Chạy ví dụ:
Phone = 12000111
Value = Tom
6. Khởi tạo đối tượng Generic
Đôi khi bạn muốn khởi tạo một đối tượng Generic:
public void DoSomething<T>()
{
// Khởi tạo đối tượng Generic
T t = new T(); // Error
}
Nguyên nhân lỗi ở trên là do kiểu tham số T không chắc chắn nó có phương thức khởi tạo (constructor) T(), vì vậy bạn cần phải thêm giàng buộc when T : new(). Hãy xem ví dụ dưới đây:
GenericInitializationExample.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GenericsTutorial
{
class GenericInitializationExample
{
// Kiểu T phải là kiểu có Constructor mặc định.
public void DoSomeThing<T>()
where T : new()
{
T t = new T();
}
// Kiểu K phải có Constructor mặc định
// và mở rộng từ lớp KeyValue.
public void ToDoSomeThing<K>()
where K: KeyValue<K,string>, new( )
{
K key = new K();
}
public T DoDefault<T>()
{
// Trả về null nếu T là kiểu tham chiếu (reference type).
// Hoặc 0 nếu T là kiểu số (int, float,..)
return default(T);
}
}
}
7. Mảng Generic
Trong C# bạn có thể khai báo một mảng Generics:
// Khởi tạo một mảng.
T[] myArray = new T[10];
GenericArrayExample.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GenericsTutorial
{
class GenericArrayExample
{
public static T[] FilledArray<T>(T value, int count)
{
T[] ret = new T[count];
for (int i = 0; i < count; i++)
{
ret[i] = value;
}
return ret;
}
public static void Main(string[] args)
{
string value = "Hello";
string[] filledArray = FilledArray<string>(value, 10);
foreach (string s in filledArray)
{
Console.WriteLine(s);
}
}
}
}
Các hướng dẫn lập trình C#
- Thừa kế và đa hình trong C#
- Bắt đầu với C# cần những gì?
- Học nhanh C# cho người mới bắt đầu
- Cài đặt Visual Studio 2013 trên Windows
- Abstract class và Interface trong C#
- Cài đặt Visual Studio 2015 trên Windows
- Nén và giải nén trong C#
- Hướng dẫn lập trình đa luồng trong C#
- Hướng dẫn và ví dụ C# Delegate và Event
- Cài đặt AnkhSVN trên Windows
- Lập trình C# theo nhóm sử dụng Visual Studio và SVN
- Cài đặt .Net Framework
- Access Modifier trong C#
- Hướng dẫn và ví dụ C# String và StringBuilder
- Hướng dẫn và ví dụ C# Property
- Hướng dẫn và ví dụ C# Enum
- Hướng dẫn và ví dụ C# Structure
- Hướng dẫn và ví dụ C# Generics
- Hướng dẫn xử lý ngoại lệ trong C#
- Hướng dẫn và ví dụ Date Time trong C#
- Thao tác với tập tin và thư mục trong C#
- Hướng dẫn sử dụng Stream - luồng vào ra nhị phân trong C#
- Hướng dẫn sử dụng biểu thức chính quy trong C#
- Kết nối cơ sở dữ liệu SQL Server trong C#
- Làm việc với cơ sở dữ liệu SQL Server trong C#
- Kết nối cơ sở dữ liệu MySQL trong C#
- Làm việc với cơ sở dữ liệu MySQL trong C#
- Kết nối cơ sở dữ liệu Oracle trong C# không cần Oracle Client
- Làm việc với cơ sở dữ liệu Oracle trong C#
Show More