Monday, March 14, 2011

Dynamic trong C# 4 - Phần 3

Trong phần này tôi sẽ tiếp tục nói đến việc tận dụng khả năng của DLR trong việc mở rộng khả năng của một lớp sẳn có.

Mở rộng lớp đang tồn tại bằng DynamicObject

Với việc sử dụng lớp DynamicObject, bạn có thể cung cấp cú pháp tốt hơn cho mã nguồn của bạn hoặc mở rộng khả năng của các thư viện đang tồn tại. Bạn có thể tận dụng các phương thức sẳn có của một class cùng với khả năng thêm các thuộc tính và phương thức một cách tự động tại thời điểm runtime mà không phải viết toàn bộ code này một cách rõ ràng.

Dưới đây là một ví dụ tận dụng khả năng của DynamicObject kết hợp với ADO.NET trong việc lấy dữ liệu bằng câu lệnh SELECT và lưu từng cột giá trị nhận được của mỗi dòng dữ liệu trong các đối tượng IDataRecord.

Để chạy được ví dụ dưới đây, bạn cần sử dụng AdventureWorks2008 Database sample có thể download từ địa chỉ: Microsoft SQL Server Product Samples: Database.
Thông thường, nếu bạn dùng ADO.NET để truy vấn và hiển thị dữ liệu như ví dụ sau đây:

private static void ReadOrderData(string connectionString)
{
    string queryString = "SELECT [SalesOrderID], [CustomerID] FROM [Sales].[SalesOrderHeader];";
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        SqlCommand command = new SqlCommand(queryString, connection);
        connection.Open();
        SqlDataReader reader = command.ExecuteReader();
        try
        {
            while (reader.Read())
            {
                Console.WriteLine(String.Format("{0}, {1}",
                    reader[0], reader[1]));
            }
        }
        finally
        {
            // Always call Close when done reading.
            reader.Close();
        }
    }
}
Trong ví dụ này, bạn thấy rằng để truy cập vào từng cột giá trị trong từng dòng đọc được, ta sẽ phải dùng reader[0] (hoặc reader["SaleOrderID"]. Với việc mở rộng IDataRecord bằng DynamicObject, bạn có thể sử dụng reader.SaleOrderID, trong ví dụ dưới đây định nghĩa một lớp có tên DataRecordDynamic:
public class DataRecordDynamic : DynamicObject
{
    private IDataRecord m_dataRecord;

    public DataRecordDynamic(IDataRecord dataRecord)
    {
        m_dataRecord = dataRecord;
    }

    public override bool TryGetMember(
        GetMemberBinder binder, out object result)
    {
        result = m_dataRecord[binder.Name];
        return (result != null);
    }
}
Lớp này đã thực hiện định nghĩa lại phương thức xác định thao tác Get của một thuộc tính động, nó thực hiện xác định giá trị bằng cách sử dụng tên của thuộc tính xem như tên cột và lấy dữ liệu cột tương ứng với tên cột đó trong row dữ liệu nhận được (= Item[string]).
Và dưới đây là ví dụ ban đầu đã được viết lại sử dụng lớp DataRecordDynamic, bạn sẽ thấy rằng bây giờ sẽ dùng row.OrderID và row.CustomerID.
private static IList<dynamic> ExecuteOrderDataReader(string connectionString)
{
    var orderDataRows = new List<dynamic>();

    string queryString = "SELECT [SalesOrderID], [CustomerID] FROM [Sales].[SalesOrderHeader];";
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        SqlCommand command = new SqlCommand(queryString, connection);
        connection.Open();
        SqlDataReader reader = command.ExecuteReader();
        try
        {
            foreach (IDataRecord record in reader)
            {
                orderDataRows.Add(new DataRecordDynamic(record));
            }

            return orderDataRows;
        }
        finally
        {
            // Always call Close when done reading.
            reader.Close();
        }
    }
}

private static void ReadOrderData2(string connectionString)
{
    var orderDataRows = ExecuteOrderDataReader(connectionString);

    foreach (var row in orderDataRows)
    {
        Console.WriteLine(String.Format("{0}, {1}", row.SalesOrderID, row.CustomerID));
    }
}
Qua ví dụ trên, bạn cũng có thể thấy được sự khác nhau giữa ExpandoObject và DynamicObject, đó là DynamicObject còn cho phép bạn tận dụng được các phương thức, thao tác và thuộc tính sẳn có của một class.

No comments:

Post a Comment