Saturday, March 12, 2011

Dynamic trong C# 4 - Phần 2

Đây là phần tiếp theo của các bài viết về từ khóa dynamic và Dynamic Language Runtime (DLR), đây là tính năng mới trong C# 4 và .NET Framework 4. Trong phần 1 đã giới thiệu về từ khóa dynamic, nội dung của bài này sẽ mô tả về DLR và hai trong số các trường hợp sử dụng thông thường của nó.

Dynamic Language Runtime

Thuật ngữ "dynamic" trong C# thường nhắc đến một trong hai khái niệm: từ khóa dynamic trong C# 4 hoặc là Dynamic Language Runtime (DLR).

DLR phục vụ hai mục đích chính. Một là cho phép liên kết giữa ngôn ngữ động và .NET Framework serves two main goals. Và hai là mang khả năng động vào C# và Visual Basic.

DLR đã được tạo ra dựa trên các bài học trong khi xây dựng IronPython (ironpython.net), là ngôn ngữ động đầu tiên được cài đặt trong .NET Framework. Trong khi làm việc với IronPython, nhóm đã tìm ra phương pháp sử dụng lại cài đặt của mình cho nhiều ngôn ngữ khác, vì vậy họ đã tạo ra một nền tảng cơ bản dùng chung cho các ngôn ngữ động trong .NET.

Sau đó DLR đã được giới thiệu trong .NET Framework 4 để hỗ trợ các tính năng động trong C# và Visual Basic. Nếu bạn chỉ cần từ khóa dynamic trong C# 4, bạn chỉ cần sử .NET Framework và trong hầu hết trường hợp nó sẽ xử lý tất cả các tương tác với DLR trong chính bản thân mình. Nhưng nếu bạn muốn cài đặt hoặc mang một ngôn ngữ động mới vào .NET, bạn cần trợ giúp từ các lớp trợ giúp bên ngoài trong dự án nguồn mở (dlr.codeplex.com) có nhiều tính năng và dịch cho việc cài đặt ngôn ngữ.

Gọi động các phương thức và truyền các tham số

Đây không phải là sự kỳ vọng rằng các bạn nên sử dụng động bất kỳ khi nào có thể thay vì các khai báo kiểu tĩnh. Việc kiểm tra lúc biên dịch là một công cụ mạnh mẽ và nhiều lợi ích giúp bạn làm việc tốt hơn. Và hơn nữa, các đối tượng động trong C# không hỗ trợ IntelliSense, mà có thể làm năng suất công việc của bản giảm xuống.

Sau đây là một ví dụ tuyệt vời cho việc sử dụng DLR, đó là việc thay thế các API reflection để triệu gọi đến các phương thức có truyền tham số.

1. Bạn hãy sử dụng Visual Studio, tạo một ứng dụng C# Console Application có tên LateBindingWithDynamic.
2. Tiếp theo, bạn hãy thêm một Class Library project trong solution hiện tại với tên MathLibrary.
3. Đặt lại tên Class1.cs của MathLibrary thành SimpleMath.cs và cài đặt lớp như sau:
public class SimpleMath { 
    public int Add(int x, int y) 
    { return x + y; } 
}
4. Tiến hành build MathLibrary và copy MathLibrary.dll vào thư mục bin/Debug của LateBindingWithDynamic (Bạn có thể dùng tính năng ShowAllFiles trong VS và kéo thả MathLibrary.dll từ thư mục bin/Debug của MathLibrary vào thư mục bin/Debug của LateBindingWithDynamic).
5. Triệu gọi phương thức Add của thư viện MathLibrary trong LateBindingWithDynamic: Có hai phương pháp triệu gọi ở đây là sử dụng các API reflection và sử dụng từ khóa dynamic.
a/ Phương thức sau sẽ gọi phương thức Add sử dụng các triệu gọi API reflection:
private static void AddWithReflection()
{
    Assembly asm = Assembly.Load("MathLibrary");

    // Get metadata for the SimpleMath type. 
    Type math = asm.GetType("MathLibrary.SimpleMath");

    // Create a SimpleMath on the fly. 
    object obj = Activator.CreateInstance(math);

    // Get info for Add. 
    MethodInfo mi = math.GetMethod("Add");

    // Invoke method (with parameters). 
    object[] args = { 10, 70 };
    Console.WriteLine("Result is: {0}", mi.Invoke(obj, args));

}
b/ Trường hợp sử dụng từ khóa dynamic:
private static void AddWithDynamic()
{
    Assembly asm = Assembly.Load("MathLibrary");

    // Get metadata for the SimpleMath type. 
    Type math = asm.GetType("MathLibrary.SimpleMath");

    // Create a SimpleMath on the fly. 
    dynamic obj = Activator.CreateInstance(math);
    Console.WriteLine("Result is: {0}", obj.Add(10, 70));
}

Trong hai trường hợp trên, bạn sẽ thấy được lợi điểm của việc sử dụng DLR, với việc sử dụng DLR giúp cho việc gọi phương thức và truyền các tham số trong đơn giản và dể hiểu hơn so với cách sử dụng API Reflection.

Khai báo phương thức và thuộc tính động lúc thực thi (Dynamic Method Bags)

Một ví dụ khác mà của dynamic có thể làm được là tạo ra nơi chứa các phương thức động (method bag), tức là các đối tượng có thể thêm và xoá các thuộc tính và phương thức lúc thực thi, và sau đó triệu gọi các phương thức này thông qua triệu gọi động (dynamic dispatch) trong C#.

Trong .NET Framework 4 có một namespace mới: System.Dynamic. Namespace này thực ra là một phần của DLR và được định nghĩa trong gói (assembly) System.Core. Các lớp System.Dynamic.ExpandoObject và System.Expando.DynamicObject cùng với từ khóa dynamic có thể giúp bạn tạo ra các cấu trúc (structure) động và hệ thống thứ bậc (hierarchic) động theo một cách đơn giản và dễ hiểu.
Sau đây là ví dụ diễn tả cách bạn có thể thêm một thuộc tính và phương thức bằng cách sử dụng lớp ExpandoObject như ví dụ dưới đây:

dynamic expando = new ExpandoObject();
expando.SampleProperty = "Đây là thuộc tính được thêm lúc thực thi";
expando.SampleMethod = (Action)(
    () => Console.WriteLine(expando.SampleProperty));
expando.SampleMethod();

Dưới đây là một ví dụ về việc đọc dữ liệu từ XML. Trong ví dụ này đã sử dụng class ExpandoObject để lưu trữ dữ liệu nhận được từ XML, bạn có thể truy cập dữ liệu này thông qua các thuộc tính tự động được thêm vào lúc đọc dữ liệu và thực hiện thêm phương thức GetFullName để mô tả khả năng đưa thêm phương thức trong lúc chạy chương trình.
Dữ liệu trong XML có cấu trúc như sau:

  
     Thanh 
     Ho Hai 
  
  
     Phuong Linh 
     Ho Hoang 
  

Và dưới đây là toàn bộ đoạn code :
public static IList<dynamic> GetExpandoFromXml(String file)
{
    var persons = new List<dynamic>();

    var doc = XDocument.Load(file);
    var nodes =
        from node in doc.Root.Descendants("Person")
        select node;

    foreach (var n in nodes) {
        dynamic person = new ExpandoObject();

        //Đọc các giá trị tương ứng với FirstName và LastName của mỗi Person
        foreach (var child in n.Descendants()) {
            // Bởi vì ExpandoObject được cài đặt interface IDictionary<string, object>
            // và xem như mỗi phần tử của Dictionary gồm có thuộc tính và giá trị
            var p = person as IDictionary<string, object>;

            //person được thêm 2 thuộc tính là FirstName và LastName
            p[child.Name.ToString()] = child.Value.Trim();
        }
        
        //Cài đặt phương thức lấy đầy đủ họ tên cho person
        person.GetFullName = (Func<string>)(() =>
        {
            return string.Format("{0}, {1}", person.FirstName, person.LastName);
        });

        persons.Add(person);
    }

    return persons;
}
Và bạn có thể truy cập dữ liệu đọc được ở trên bằng các thuộc tính và phương thức đã được thêm vào cho mỗi đối tượng ExpandoObject lúc thực thi như sau:
IList<dynamic> persons = GetExpandoFromXml("Persons.xml");
foreach (var p in persons)
{
    Console.WriteLine(p.GetFullName());
}
Trên đây là hai trong số những kịch bản mà bạn có thể sử dụng DLR trong C# 4, trong những bài tiếp theo, tôi sẽ mô tả về các tính năng cao cấp khác của DLR.

No comments:

Post a Comment