Trong bài viết này, chúng ta sẽ cùng tìm hiểu Properties và Indexers trong lập trình hướng đối tượng C#.
1. Properties
– Thuộc tính – Property là một thành viên (member) của một class, struct hay interface. Nó là mở rộng của một trường (field). Property cho phép bạn truy cập vào một field hoặc thay đổi giá trị của field đó, mà không cần thiết phải truy cập trực tiếp vào field.
– Một property là một thành viên cung cấp một cơ chế linh hoạt để đọc, ghi hoặc tính toán giá trị của một private field. Các properties có thể được sử dụng như thể chúng là những public data members, nhưng chúng thực sự là các phương thức đặc biệt (special methods) được gọi là bộ truy cập (accessors). Điều này cho phép dữ liệu được truy cập dễ dàng, linh hoạt mà vẫn đảm bảo được sự an toàn.
Xem thêm: So sánh properties và fields.
– Có 4 loại properties:
- Read-Write Property: có đủ phương thức get (để lấy dữ liệu của field), set (để thiết lập dữ liệu cho field).
- Read only Property: chỉ có phương thức get.
- Write only Property: chỉ có phương thức set.
- Auto-Implemented Property: cách viết ngắn gọn của loại 1. Read-Write Property.
Trong C# 3.0 trở lên, các thuộc tính được implemented tự động làm cho khai báo thuộc tính ngắn gọn hơn khi không có logic bổ sung nào được yêu cầu trong các bộ truy cập (accessors) thuộc tính. Khi bạn khai báo thuộc tính (name2, address2, address3, age2) như trong ví dụ sau, trình biên dịch sẽ tạo một trường (field) sao lưu riêng, ẩn danh (anonymous) chỉ có thể được truy cập thông qua get và set accessors.
– Ví dụ:
{
class SampleProperty
{
// 1. Read-Write Property
private string name1;
public string Name1
{
get { return Name1; }
set { Name1 = value; }
}
// 2. Read only Property
private string address1;
public string Address1
{
get
{
return address1;
}
}
// 3. Write only Property
private int age1;
public int Age1
{
set
{
if (1 > value)
age1 = 1;
else
age1 = value;
}
}
// 4. Auto-Implemented Property
// Cách viết ngắn gọn của // 1. Read-Write Property
public string name2 { get; set; }
// Cách viết ngắn gọn của // 2. Read only Property
public string address2 { get; }
public string address3 { get; private set; }
// Write only Property
public string age2 { private get; set; }
}
}
[/code]
※ Tip: Chọn vào tên field, rồi nhấn tổ hợp phím Ctrl + R + E + Enter để sinh get/set tự động.
2. Indexers
– Indexer cho phép các instances của class hoặc struct được lập chỉ mục (index) giống như các mảng (array), nó cho phép duyệt các đối tượng của một lớp giống như duyệt mảng (bằng cách sử dụng cặp dấu []).
– Một số đặc điểm của indexer:
- Indexer còn được gọi là smart array (mảng thông minh), hay prototype của tham số.
- Indexer có thể được nạp chồng (overload).
- Indexer có thể được include như là một interface member.
- Indexer không hỗ trợ ref và out parameter.
Xem thêm: Cách truyền tham trị, tham chiếu trong C#.
– Cú pháp khai báo:
<phạm vi truy cập> <đối tượng dữ liệu> this[<kiểu dữ liệu> index] { get { // trả về giá trị được xác định bởi index } set { // thiết lập giá trị được xác định bởi index } }
Sử dụng của Indexer trong C#:
– Việc khai báo hành vi của một indexer là tương tự như một property. Bạn sử dụng get accessor và set accessor để định nghĩa một indexer.
– Việc định nghĩa một property bao gồm việc cung cấp một tên thuộc tính. Indexer không được định nghĩa với các tên, mà với từ khóa this sẽ tham chiếu tới instance của đối tượng. Ví dụ sau đây minh họa khái niệm này:
■ Tạo class Product.cs
{
class Product
{
public int id { get; set; }
public string name { get; set; }
}
}[/code]
■ Tạo class ProductList.cs
{
class ProductList
{
public Product[] arrProduct { get; set; }
// Indexer
public Product this[int index]
{
get
{
if (0 > index || index >= arrProduct.Length)
//return null;
throw new IndexOutOfRangeException("Index not valid!!!");
else
return arrProduct[index];
}
set
{
if (0 > index || index >= arrProduct.Length)
throw new IndexOutOfRangeException("Index not valid!!!");
else
arrProduct[index] = value;
}
}
// Overload indexer, nhận vào 1 biến kiểu string
// Để search trong list product,
// có tên sản phẩm trùng với tên sản phẩm user input vào hay không.
public Product this[string name]
{
get
{
for (int ii = 0; ii < arrProduct.Length; ii++)
{
if (arrProduct[ii].name.ToUpper().Equals(name.ToUpper()))
{
return arrProduct[ii];
}
}
return null;
}
}
}
}[/code]
■ Class xử lý chính Program.cs
namespace MinhHoangBlog
{
class Program
{
static void Main(string[] args)
{
// Tạo đối tượng list sản phẩm
ProductList pList = new ProductList();
// Trong danh sách sp này sẽ có 5 sản phẩm
pList.arrProduct = new Product[5];
// ★ Dùng theo cách thông thường
/*
for (int ii = 0; ii < pList.arrProduct.Length; ii++)
{
//Đối với mỗi sp thứ i thì set thông tin
pList.arrProduct[ii] = new Product();
pList.arrProduct[ii].id = ii;
pList.arrProduct[ii].name = string.Format("P{0}", ii);
}
// In thông tin SP
for (int ii = 0; ii < pList.arrProduct.Length; ii++)
{
Console.WriteLine("id: " + pList.arrProduct[ii].id);
Console.WriteLine("name: " + pList.arrProduct[ii].name);
Console.WriteLine("———————-");
}
*/
// ★ Dùng Indexer
for (int ii = 0; ii < pList.arrProduct.Length; ii++)
{
pList[ii] = new Product();
pList[ii].id = ii;
pList[ii].name = string.Format("P{0}", ii);
}
// In thông tin SP
for (int ii = 0; ii < pList.arrProduct.Length; ii++)
{
Console.WriteLine("id: " + pList[ii].id);
Console.WriteLine("name: " + pList[ii].name);
Console.WriteLine("———————-\n");
}
// ★ Dùng overload Indexer
Console.Write("Nhap vao ten san pham: ");
string name = Console.ReadLine();
Product sanpham = pList[name];
if (null != sanpham)
{
Console.WriteLine("TIM THAY SAN PHAM!");
}
else
{
Console.WriteLine("KHONG TIM THAY.");
}
Console.ReadKey();
}
}
}[/code]