Có thể nói nét chủ đạo trong .NET 4.0 đó là lập trình động (dynamic programming). Các đối tượng (object) ngày nay trở nên động (dynamic) theo ý nghĩa là cấu trúc và hành vi của nó không bị bó buộc bởi kiểu dữ liệu tĩnh (static) như trước đó, đồng thời trình biên dịch không cần biết kiểu dữ liệu của đối tượng trong quá trình biên dịch chương trình. Điều này sẽ rất có ích khi chương trình cần phải tương tác với các đối tượng từ các ngôn ngữ lập trình động giống như Python hoặc Ruby, hay là làm việc với các đối tượng mà có sự thay đổi về mặt cấu trúc như HTML hoặc DOM. Qua đó chúng ta có thể sử dụng nhiều ngôn ngữ khác nhau trên cùng một ứng dụng. Các đoạn mã của C#, VB.NET, IronPython,Javascripts… có thể hòa trộn với nhau để tạo ra một chương trình hoàn chỉnh.
Với dynamic trong .NET 4.0, khi lập nhận được một đối tượng, chúng ta không cần phải quan tâm đối tượng đó đến từ COM, IronPython hay HTML DOM hoặc Reflection. Chúng ta có thể sẵn sàng áp dụng các phép toán cho nó và để cho môi trường thực thi quyết định phép toán nào sẽ áp dụng cho đối tượng nào.
Lấy ví dụ:
Gọi phương thức từ lớp C#
Calculator calc = GetCalculator(); int sum = calc.Add(10, 20);
object calc = GetCalculator(); Type calcType = calc.GetType(); object res = calcType.InvokeMember("Add", BindingFlags.InvokeMethod, null, new object[] { 10, 20 }); int sum = Convert.ToInt32(res);
ScriptObject calc = GetCalculator(); object res = calc.Invoke("Add", 10, 20); int sum = Convert.ToInt32(res);
dynamic calc = GetCalculator(); int sum = calc.Add(10, 20);
. NET 4.0 giới thiệu một lớp mới gọi là DynamicObject cho phép định nghĩa các hành vi có thể được thực thi trong quá trình chạy. Đây là một đặc trưng rất mới trong .NET 4.0. Chúng ta biết rằng các đối tượng trong .NET 3.5 và trước đó đều phải xác định cấu trúc và các hành vi trong quá trình biên dịch. Với DynamicObject cho phép các lập trình viên xây dựng các đối tượng một cách linh hoạt hơn. Việc lấy giữ liệu hay xác định hành vi cho đối tượng có thể được quyết định và thực thi trong quá runtime. Lập trình viên sẽ viết mã để điều khiển quá trình lấy và thao tác giữ liệu cho đối tượng. Điều này sẽ rất có ích khi chúng ta làm việc các đối tượng có sự thay đổi về mặt cấu trúc như XML hay ADO object.
Lấy ví dụ: Bài toán đọc một đối tượng XML
Trước hết chúng ta khai báo một lớp kế thừa từ DynamicObject
public class EasierXML : DynamicObject { private XDocument _xml = new XDocument(); public EasierXML(string Xml) { this._xml = XDocument.Parse(Xml); } public override bool TryGetMember(GetMemberBinder binder, out object result) { string nodeName = binder.Name; result = _xml.Element("test").Element(nodeName).Value; return true; } }
dynamic easierXML = new EasierXML(@"<test><node1>Alpha</node1><node2>Beta</node2></test>"); Console.WriteLine(easierXML.node1); Console.WriteLine(easierXML.node2);
truy vấn tài liệu XML và trả lại các nút riêng lẻ. Trong trường hợp cấu trúc XML có sự thay đổi, có một số node nào đó được thêm, chúng ta chỉ việc gọi đến easierXML.node3, easierXML.node4,.. mà không cần phải thay đổi đến lớp EasierXML
Một ví dụ khác, sử dụng DynamicObject còn giúp chương trình giảm thiểu được các lỗi phát sinh trong quá trình ép kiểu giữ liệu khi chúng ta làm việc với các đối tượng ADO.
Theo cách lập trình thông thường: chúng ta phải tiến hành ép kiểu mỗi khi đọc giá trị từ database
com.CommandText = "SELECT * FROM Employees"; using (IDataReader reader = com.ExecuteReader()) { while (reader.Read()) { int id = Int32.Parse(reader["EmployeeID"].ToString()); string firstName = reader["FirstName"].ToString(); DateTime dob = DateTime.Parse(reader["BirthDate"].ToString()); } }
com.CommandText = "SELECT * FROM Employees"; using (IDataReader reader = com.ExecuteReader()) { dynamic dr = new DynamicReader(reader); while (reader.Read()) { int id = dr.EmployeeID; string firstName = dr.FirstName; DateTime dob = dr.BirthDate; } }
Trên đây là nét đặc trưng trong nền tảng ngôn ngữ .NET 4.0 đó là dynamic programming. Vậy chúng ta có thể ứng dụng nó vào các bài toán thực tế như thế nào? Lấy một ví dụ cho một ứng dụng desktop client sử dụng WPF. Như chúng ta biết rằng WPF tách biệt phần hiển thị của ứng dụng với các đoạn mã logic. Điều đó giúp cho các lập trình viên và các nhà thiết kế có thể làm việc độc lập mà vẫn không ảnh hưởng tới quá trình phát triển của ứng dụng. Các ứng dụng ngày nay thường được phát triển thông qua kiến trúc nhiều tầng. Một kiến trúc căn bản bao gồm tầng thể hiện, tầng logic nghiệp vụ và tầng thao tác dữ liệu. Thông thường, tầng thể hiện sẽ phát sinh nhiều yêu cầu thay đổi nhất từ phía khách hàng, trong khi tầng thao tác giữ liệu phải đảm bảo tính ổn định về mặt kiến trúc. Dó đó một kiến trúc tốt cần đảm bảo những yêu cầu thay đổi từ phía khach hàng không làm ảnh hưởng quá nhiều đến thiết kệ hiện có của ứng dụng, đặc biệt là các thiết kế liên quan đến thao tác giữ liệu.
Xét một ví dụ sau: Quản lý thông tin cá nhân
Giữ liệu được lưu trong 1 file XML có cấu trúc:
<?xml version="1.0" encoding="utf-8"
?> <People> <Person>
<FirstName>Quang</FirstName>
<LastName>Lê</LastName> </Person> <Person>
<FirstName>Sơn</FirstName>
<LastName>Hà</LastName> </Person>
Thực thể (Business Entity)
Khai báo một lớp Person
public class Person { public string FirstName { get; set; } public string LastName { get; set; } }
Lấy giữ liệu từ nguồn (trong ví dụ này sử dụng XML là nguồn lưu trữ giữ liệu, tương tự chúng ta có thể thay thế XML bằng CSDL có cấu trúc như SQL Server, Oracle)
public IEnumerable<Person> GetData() { XDocument oDoc = XDocument.Load("People.xml"); var myData = from info in oDoc.Descendants("Person") select new Person { FirstName = info.Element("FirstName").Value, LastName = info.Element("LastName").Value, }; return myData.ToList<Person>(); }
Gắn kết giữ liệu và hiển thị lên controls:
<DataGrid Name="myDataGrid" VerticalAlignment="Top" ItemsSource="{Binding}" AutoGenerateColumns="False" > <DataGrid.Columns> <DataGridTextColumn x:Name="firstNameColumn" Binding="{Binding Path=FirstName}" Header="First Name" Width="SizeToHeader" /> <DataGridTextColumn x:Name="lastNameColumn" Binding="{Binding Path=LastName}" Header="Last Name" Width="SizeToHeader" /> </DataGrid.Columns> </DataGrid>
Vậy làm sao để giải quyết vấn đề trên?
Sử dụng dynamic binding (gắn kết động)
Thực thể (Business Entity)
Triển khai DynamicObject. Lớp này có thể sử dụng cho tất cả các nguồn giữ liệu là XML mà không phân biệt cấu trúc của nó. Nhiệm vụ của nó là lấy ra một cách chính xác giá trị trong các thẻ XML
class DynamicXML : DynamicObject { XElement _element; public ReadXML(XElement e) { _element = e; } public override bool TryGetMember(GetMemberBinder binder, out object result) { //Triển khai phương thức lấy giá trị của đối tượng } }
Lấy giữ liệu từ nguồn và trả về đối tượng dynamic
dynamic GetPersonData() { var root = XElement.Load("People.xml"); dynamic xml = new DynamicXML(root); return xml.Person; }
Gắn kết giữ liệu và hiển thị lên controls
<DataGrid Name="myDataGrid" VerticalAlignment="Top" ItemsSource="{Binding}" AutoGenerateColumns="False" > <DataGrid.Columns> <DataGridTextColumn x:Name="firstNameColumn" Binding="{Binding Path=FirstName}" Header="First Name" Width="SizeToHeader" /> <DataGridTextColumn x:Name="lastNameColumn" Binding="{Binding Path=LastName}" Header="Last Name" Width="SizeToHeader" /> </DataGrid.Columns> </DataGrid>
<DataGridTextColumn x:Name="ageColumn" Binding="{Binding Path=Age}" Header="Age" Width="SizeToHeader" /> <DataGridTextColumn x:Name="isMaleColumn" Binding="{Binding Path=IsMale}" Header="Is Male" Width="SizeToHeader" />
0 comments:
Post a Comment