Jul 8, 2010

Điều gì mới ở C# 4.0

Vấn đề là mằn trong vấn đề... Lọ mọ trên mạng vớ dc bài viết giới thiệu về C# 4.0 nên copy về đây. Không rõ nguồn gốc xuất sứ bài này do ai viết nhưng mà tìm dc bên ddth.com

Thấy cũng hay, bổ ích nhiều vấn đề mới ...

Khi quyển sách này đang được viết, thì phiên bản mới nhất của Microsoft là Visual Studio 2010 Beta 2 và .NET Framework 4.0 Beta 2 đang được giới CNTT tải về để nghiên cứu. Bắt đầu từ ngày 11/02/2010 sắp tới, Microsoft tổ chức những hội nghị mở rộng tại nhiều thành phố lớn trên toàn thế giới để giới thiệu phiên bản mới nhất của Visual Studio và .NET Framework, sẽ được tung ra thị trường vào ngày 22/03/2010.

Thứ nhất, vì phiên bản Visual Studio-2010 chưa được tung ra thị trường, cho nên những chức năng mới của Visual Studio-2010 được viết trong sách này, đều chưa được chính thức công nhận, và có thể có những thay đổi. Tuy nhiên, có thể nói rằng, sẽ không có bất cứ một thay đổi quan trọng nào có thể xảy ra.

Thứ hai, mặc dầu phiên bản mới sắp được phát hành, tất cả những tư liệu dẫn chứng cho những mã nguồn, cũng như những mã nguồn mẫu trong quyển sách này, vẫn là những gì nồng cốt nhất cho một lập trình C#, ngày hôm nay, cũng như sau khi Visual Studio-2010 được phát hành, và chắc chắn rằng vẫn còn là những nồng cốt của một chương trình C# cho tới phiên bản kế tiếp sau phiên bản Visual Studio-2010.

Những chủ đề (themes) của phiên bản C# mới.

Với phiên bản Visual Studio-2010, để có thể thống nhất về con số của những phiên bản, C# 2010 được gọi là C# 4.0, cùng một hệ số với phiên bản .NET Framework 4.0. Do đó, các bạn nên bắt đầu làm quen với cách gọi này: C# 4.0, thay vì C#-2010.

Chủ đề chính được Microsoft hoạch định cho phiên bản C# 4.0 là “Năng Động (Dynamic)”. Tất cả những chức năng mới của phiên bản C# 4.0 đều được phát triển chung quanh hai chữ “năng động”. Và như các bạn đã được biết, lớp đối tượng nền của tất cả các lớp đối tượng trong một lập trình C# là System.Object. Do đó, System.Object bắt buộc phải trở thành một lớp đối tượng có tính năng động. Nói một cách khác, mục tiêu của Microsoft cho phiên bản .NET Framework 4.0 nói chung, và C# nói riêng, là C# phải trở thành một ngôn ngữ có những lớp đối tượng năng động

Nhưng thế nào là lớp đối tượng năng động? Một lớp đối tượng năng động là một lớp đối tượng mà cấu trúc(structure) và trạng thái (behavior) của nó không bị bó buộc hoặc lệ thuộc vào những trạng thái tĩnh (static). Nói một cách khác, một đối tượng lớp không cần phải định nghĩa trước khi khởi tạo, mà có thể được định nghĩa khi bắt đầu khởi tạo trong lúc phần mềm đang vận hành. Và nói một cách khác nữa, một lớp đối tượng năng động là một lớp đối tượng mà biên trình (csc.exe) không biết một tí gì về đối tượng đó khi biên lập.

Những đối tượng (objects) dưới đây là những điển hình của một đối tượng năng động

Đối tượng của những ngôn ngữ lập trình năng động, như Pyphon hoặc Ruby.
Những đối tượng COM được truy cập qua giao ước IDispatch.
Những dạng đối tượng nguyên thuỷ của .NET có thể truy cập qua phép đối xứng (reflection).
Những đối tượng có cấu trúc thay đổi trong khi vận hành, như HTML DOM.

Mặc dầu thế, C# vẫn là một ngôn ngữ nặng tích chất không thay đổi (static), nhưng có khả năng tạo lên được những lớp đối tượng năng động.

Chủ đề thứ hai, hay mục tiêu thứ hai cho C#, là “cùng tiến hóa” với Visual Basic. Cùng tiến hóa, nhưng vẫn giữ những đặc tính riêng biệt. Nói một cách khác, 2 ngôn ngữ sẽ cùng có chung những chức năng và hiệu năng, nhưng vẫn là 2 ngôn ngữ riêng biệt với những cú pháp riêng biệt.

Những chức năng mới của C# được chia ra làm 4 thành phần, như sau:

1. Truy vấn năng động (dynamic lookup)
2. Tham số tên và tham số tuỳ chọn (Named and option parameters)
3. Chức năng giao tiếp với những COM đã được lựa chọn
4. Biến dạng (variance)


Truy vấn năng động (dynamic lookup)
Truy vấn năng động là những chức năng có thể tạo dựng được những hàm, những toán tử và chỉ mục, những thuộc tính và trường truy cập, và những đối tượng sự-tác có thể vượt qua những quy tắc đòi hỏi chỉ định dạng trước khi được khởi tạo.

Truy vấn năng động cho phép một phần mềm có thể kích hoạt được những đối tượng trong lúc vận hành mà không phải lưu tâm đến việc những đối tượng đó thuộc về những dạng nào, và từ đâu tới( COM, HTML DOM, Python, hoặc đối xứng). Chỉ cần áp dụng những thao tác xử lý vào một đối tượng, và để cho bộ vận hành thẩm định những thao tác đó.

Chức năng này cho các bạn sự uyển chuyển và giản dị hóa mã nguồn trong một thảo chương, nhưng đổi lại, dạng của một đối tượng không được thẩm định trong những thao tác truy vấn. Lớp đối tượng năng động không được thẩm tra khi biên lập, do đó, nếu có những lỗi lầm, những lỗi lầm đó chỉ xảy ra khi vận hành. Nói một cách khác, phần mềm của các bạn có nhiều hy vọng bị treo trong khi vận hành. Thông thường, khi phần mềm bị treo vì những lý do có liên quan đến việc xử lý của một đối tượng năng động, sẽ không có gì tổn hại đến hệ điều hành. Nhưng đôi khi, những lỗi lầm này có thể ảnh hưởng đến tính chất bảo vệ hệ thống phần mềm. Do đó, C# cho các bạn có sự tùy chọn giữa năng động và không năng động trước khi khởi tạo một đối tượng.

Dạng năng động (dynamic type)

Với C# 4.0, một dạng tĩnh có thể định dạng năng động. Với dạng tĩnh năng động, các bạn có thể tạo dựng những thao tác với những điều kiện chỉ có thể có trong lúc vận hành:

Code:
Dynamic năngĐộng = GetDynamicObject(...); năngĐộng.M(7);

Với 2 hàng mã nguồn mẫu trên, biên trình csc.exe không thể thẩm định tên và những tham số thuộc đối tượng năngĐộng trên. Do đó, các bạn có thể dùng bất cứ tên (cho thuộc hàm) gì, và bất cứ một tham số nào. Khi phần mềm được vận hành, bộ vận hành DLR mới có thể thẩm định năngĐộng thuộc đối tượng gì. năngĐộng có thuộc hàm M() không, và thuộc hàm năngĐộng.M() có phải là một thuộc hàm có một tham số thuộc dạng số không.

Các bạn có thể gán bất cứ một giá trị nào cho một đối tượng năng động, và một đối tượng năng động cũng có thể gán cho bất cứ một dạng đối tượng nào, như sau:

Code:
class Program {
static void Main(string[] args) {
dynamic d = 199; int i = d; string str = d; Form frm = d;
}
}



Vận hành năng động

Không những chỉ có thuộc hàm có thể...năng động, mà tất cả những gì thuộc về truy cập đều có thể năng động, kể cả uỷ nhiệm:

Code:
dynamic d = 199; d.f = d.P; // truy cap thuoc tinh d["Hai"] = d["Ba"]; // truy van / cap nhat voi chi muc
int i = d + 3; // dung toan tu string s = d(5,7); // Goi nhu mot uy nhiem

Khi vận hành, thao tác xử lý năng động được kích hoạt tuỳ theo tính tự nhiên của những đối tượng năng động dưói đây:

Đối tượng COM

Nếu đối tượng năng động là một đối tượng được định nghĩa từ một linh kiện COM, những thao tác xử lý được gửi qua IDispatch của đối tượng COM đó. Điều này cho phép chương trình gọi những hàm của nhiều dạng COM không có PIA (Primary Interop Assembly), và lệ thuộc vào những chức năng của COM không có trong ngôn ngữ C#, chẳng hạn như thuộc tính chỉ mục, hoặc thuộc tính mặc định.

Đối tượng năng động (dynamic objects)

Nếu đối tượng năng động là một đối tượng năng động thuộc dạng IDynamicObject, thao tác xử lý sẽ được khởi động tại tầng đối tượng. Do đó, một đối tượng định dạng IDynamicObject có thể hoàn toàn thay đổi phương tiện của những thao tác vận hành. Điều này rất thông dụng trong những ngôn ngữ năng động như IronPython hoặc IronRuby. Đối tượng thuộc dạng IDynamicObject còn có thể được dùng bởi HTML DOM.

Đối tượng lớp thuộc về .NET

Nếu không thuộc 2 đối tượng trên, thì đó là một đối tượng lớp .NET thông thường, và những thao tác xử lý được vận hành bằng cách dùng đối xứng (reflection) trên dạng lớp của đối tượng (để tìm ra những dẫn chứng), thí dụ như:

Code:
public void DoiTuongNangDongNET() {
dynamic d1 = new TiepThiVien(“TT001”);
dynamic d2 = new NhanCong(“NC001”);
string s;
d1.M(s, d2, 3, null);
}

Vì hàm M() được gọi từ tầng đối tượng dynamic, biên trình sẽ không thẩm định ngữ nghĩa của hàm M(), mà chỉ lưu giữ thông tin M(2,d2,3,null) cho đến khi vận hành, nhường quyền thẩm định cho bộ vận hành DLR của .NET. Những thông tin này chủ yếu có những ý nghĩa như sau:

“Khởi động hàm M() với những tham số”:
1. Chuỗi ký tự
2. đối tượng năng động (d2)
3. hằng số 3
4. null

Khi vận hành, vì d1 không phải là một đối tượng COM, cũng không được định dạng IDynamicObject, nên bộ vận hành dùng phép đối xứng để truy vấn những dẫn chứng của đối tượng d1 như sau:

Phép đối xứng được dùng để lấy thông tin về 2 đối tượng d1 và d2 và biết được d1 thuộc dạng TiepThiVien, và d2 thuộc dạng NhanCong.
Tìm thuộc hàm M() có dấu ký (string, NhanCong, int, object).
Nếu tìm thấy thuộc hàm, M() sẽ được kích hoạt. Nếu không, lỗi sẽ được ném về hàm DoiTươngNangDongNET().

Lý giải cho những tham số thuộc dạng dynamic (năng động)

Ngay cả trường hợp đối tượng nhận được hàm gọi là một đối tượng thuộc dạng lớp đã được định nghĩa, thông tin về hàm được gọi vẫn được lý giải khi vận hành. Điều này xảy ra nếu hàm được gọi có một hay nhiều tham số thuộc dạng dynamic:

Code:
public void DoiTuongNangDongNET() {
TiepThiVien d1 = new TiepThiVien(“TT001”);
dynamic d2 = new NhanCong(“NC001”); s
tring s;
d1.M(s, d2, 3, null);
}

Trong hàm mẫu trên, tuy d1 là một đối tượng lớp thuộc dạng TiepThiVien, nhưng thuộc hàm M() của nó có một tham số được định với dạng dynamic. Do đó, kết quả vẫn là một dạng năng động, và sẽ được biên lập để được xử lý bởi bộ vận hành DLR theo mô hình năng động.
Những giới hạn của việc dùng đối tượng năng động
Bộ vận hành DLR có những giới hạn dưới đây:

Đối tượng năng động có thể được khởi tạo cho một dạng lớp, nhưng C# 4.0 vẫn chưa có những cú pháp hổ trợ cho việc này.
Bộ vận hành DLR không có khả năng tìm thấy những hàm nới rộng. Do đó, chương trình sẽ gặp lỗi vận hành nếu gọi hàm nới rộng trên một tầng đối tượng năng động.
Hàm vô danh không thể dùng như một tham số khi gọi một hàm trên tầng đối tượng năng động.

Tham số tên và tham số tuỳ chọn

Tham số tên và tham số tuỳ chọn là 2 chức năng khác nhau, nhưng thường được dùng với nhau. Tham số tùy chọn cho các bạn sự lựa chọn dùng hoặc không dùng tham số đó khi gọi một hàm có tham số tùy chọn, trong khi tham số tên là phương pháp để đưa một tham số qua một hàm bằng cách dùng tên của tham số thay vì dùng vị thế của tham số đó theo thứ tự từ trái qua phải.

Có nhiều API, đặc biệt là những linh kiện COM như Microsoft Office API, đã được viết để cung cấp những hàm dùng tham số tên và tham số tùy chọn. Hiện tại (khi chưa có phiên bản C# 4.0), một lập trình C# gặp phải rất nhiều khó khăn khi muốn gọi những hàm có tham số tên và tham số tuỳ chọn. Đôi khi, phải gọi một hàm có hơn 30 tham số, và phải đưa qua hơn 30 tham số đó, thay vì chỉ đưa qua những tham số tuỳ chọn bằng cách dùng tên của tham số.

Và ngay cả những hàm được định nghĩa trong những lớp đối tượng mà các bạn đã tạo lên, muốn gọi những hàm đó, phải đưa qua đầy đủ những tham số thích hợp đã được định nghĩa.

Tham số tuỳ chọn (optional parameters)

Muốn định nghĩa một hàm có những tham số tuỳ chọn, các bạn cần phải cho những tham số đó một giá trị mặc định, như sau:

public void HamThamSoTuyChon(int I1, int I2 = 0, bool b1 = true){}

Trong hàm mẫu trên, hai tham số I2 và B1 là những tham số tuỳ chọn, và không bắt buộc phải dùng khi gọi hàm HamThamSoTuyChon():

Code:
HamThamSoTuyChon(5); // Gọi với 1 tham số HamThamSoTuyChon(5,10); // Gọi với 2 tham số
HamThamSoTuyChon(5,10, false); // Gọi với tất cả tham số

Tham số tên (dùng với tham số tùy chọn)

C# 4.0 không hổ trợ cú pháp không dùng tham số tùy chọn có vị thế ở chính giữa bằng cách dùng những dấu phảy như sau:

Code:
HamThamSoTuyChon(5,, false); // Gọi với 2 tham số 1 và 3 (không được hổ trợ)

Cú pháp như trên, nếu được hổ trợ, sẽ đưa đến hậu quả nhầm lẫn và khó đọc nếu có hàng chục dấu phảy khi gọi một hàm. Các bạn sẽ khó nhận ra tham số nào đã được dùng, và tham số nào đã không được dùng. Với tham số tên, các bạn có thể chỉ định tham số tuỳ chọn khi gọi một hàm có nhiều tham số tùy chọn, như sau:
Code:
HamThamSoTuyChon(5,B1: false); // Gọi với 2 tham số 1 và 3
HamThamSoTuyChon(5,B1:false,I2:10 ); // Gọi với 3 tham số, nhưng không theo thứ tự

Với cú pháp được hổ trợ trên, khi gọi một hàm có nhiều tham số tùy chọn, các bạn có thể chỉ định tham số được dùng bằng cách dùng tên của tham số đó. Không cần phải lý giải thêm, chắc chắn các bạn đã thấy sự dễ dàng cho người viết, và sự dễ hiểu cho người đọc cho những cú pháp này.

Lý giải vận hành trên những hàm nạp chồng

Tham số tên và tham số tùy chọn, khi được dùng để gọi những hàm nạp chồng, dĩ nhiên, ảnh hưởng đến bộ vận hành .NET, nhưng thật ra rất giản dị khi bộ vận hành phải lý giải một hàm được gọi.

Dấu ký sẽ được dùng nếu tất cả những tham số đã dùng đều là những tham số tuỳ chọn, hoặc tất cả đều có tên, hoặc tất cả đều nằm theo vị thế đã được định nghĩa.

Luật “chính-xác-hơn” (betterness) sẽ được dùng cho những tham số được chỉ định (và bác bỏ những tham số tuỳ chọn).

Nếu 2 dấu ký bằng nhau, dấu ký nào có tất cả tham số sẽ được chọn. Thí dụ như, nếu các bạn đã có 4 hàm nạp chồng M(...) được định nghĩa như sau:
Code:
M(string s, int i = 1) {

}

M(object o) {

}

M(int i, string s = “Chào”) {

}

M(int i) {

}

Và mã nguồn mẫu dưới đây gọi hàm M()
M(5);

Trong đoạn mã mẫu trên, các bạn có thể nhận ra, M(string 2, int i=1) không được dùng, vì 5 là một hằng số không thể nào chuyển hóa (suy định) qua dạng string. M(int I, string s = “Chào”) có thể được dùng vì tham số thứ 2 là một tham số tùy chọn. M(int i) cũng có thể được dùng.

Nhưng sau cùng, M(int I) sẽ được dùng để gọi, vì không có tham số tùy chọn.

Chức năng cho COM interop

Đây có lẽ là một chức năng sẽ được rất nhiều người ưa thích. Hãy nghĩ đến việc các bạn có thể dùng những gì sẵn có trong Exel để hiển thị những dữ liệu trong CSDL của bạn như một bảng Exel thường dùng ở các văn phòng, và có thể hiển thị những đồ họa (graphs) đẹp mắt được người xử dụng ưa chuộng.

Nhập khẩu năng động (dynamic import)

Các bạn có thể dùng từ khóa using để nhập khẩu một linh kiện COM (được hổ trợ), và sau đó khởi tạo một đối tượng Exel để dùng trực tiếp (thay vì những cách dùng kiểu ép dạng cũ):

Code:
excel.Cells[1, 1].Value = "Chào" // Thay vì ((Excel.Range)excel.Cells[1, 1]).Value2 = "Chào";
Excel.Range range = excel.Cells[1, 1];
// Thay vì Excel.Range range =(Excel.Range)excel.Cells[1, 1];


Vận hành không cần tới PIA (Program Interop Assemblies)

PIA là những linh kiện .NET có kích thước lớn được tạo dựng từ những linh kiện COM để có thể khởi tạo những dạng vững mạnh (được định nghĩa trong linh kiện COM) khi dùng với một lập trình C#. PIA cung cấp những hổ trợ tốt đẹp khi các bạn thiết kế một phần mềm. Đổi lại, trong lúc vận hành, những linh kiện có kích thước lớn này, khi được đưa vào bộ nhớ, có những tác dụng không tốt đến phần mềm của các bạn. Không những thế, lại là nguyên nhân có thể làm cho phần mềm của các bạn không thể vận hành vì lý do không có phiên bản COM thích hợp.

Chức năng no-PIA (không cần tói PIA) cho phép phần mềm của các bạn tiếp tục dùng PIA trong lúc thiết kế, nhưng không cần tới PIA khi vận hành. Thay vì đó, biên trình csc.exe đưa thẳng những phần đã được dùng từ PIA vào phần mềm của các bạn.

Loại bỏ tham số dạng tham chiếu (ref)

Nhiều linh kiện COM có những hàm nhận những tham số có dạng ref (tham chiếu). Không giống như tham số dạng tham chiếu của C#, dạng tham số tham chiếu của COM vẫn là những tham số có giá trị thực.
Do đó, C# 4.0 sẽ loại bỏ tất cả những dạng tham chiếu khi gọi một hàm của COM bằng cách tạo những biến từ tạm thời để lưu giữ giá trị của những tham số, và dùng những biến từ đó khi vận hành.

Hổ trợ dạng khả biến (variance)

Trong chương III - 10, các bạn đã được hướng dẫn về những dạng tập hợp chung mẫu (System.Collections.Generic). Các bạn có thể sẽ ngạc nhiên, khi biết, hàng mã nguồn thứ 2 dưới đây là một hàng mã nguồn có lỗi biên lập:

Code:
IList mangChuoi= new List(); IList mangDoiTuong = mangChuoi; // Lỗi biên lập IEnumerable mangDoiTuong2 = mangChuoi; // Lỗi biên lập

Hàng mã nguồn trên bị lỗi, vì biến từ mangChuoi đã không được định nghĩa đồng dạng với mảngDoiTuong. C# không hổ trợ sự chuyển dạng trên, vì có lý do rất chính đáng, vì hai biến từ mảng trên có thể được thao tác nhầm lẫn như sau:

Code:
mangDoiTuong[0] = 5.15d; string strTest = mangChuoi[0];

Một đối tượng dạng Object có thể lưu giữ một giá trị dạng double, nhưng một chuỗi ký tự thì không thể. Mặc dù một đối tượng dạng Object có thể lưu giữ một giá trị dạng chuỗi ký tự, nhưng khi có những gán ghép giá trị giống như những đoạn mẫu trên, chương trình sẽ bị lỗi vận hành.

Tuy nhiên, nếu những mảng tập hợp trên được dùng với dạng khả biến (variance), mã nguồn sẽ không bị lỗi biên lập.

Dạng đồng biến (covariance)

Với C# 4.0, giao ước IEnumerable sẽ được định nghĩa với cú pháp và ngữ nghĩa như sau:

Code:
public interface IEnumerable : IEnumerable {
IEnumerator GetEnumerator();
}

public interface IEnumerator : IEnumerator {
bool MoveNext();
T Current { get; }
}

Chỉnh từ out trong những định nghĩa trên chỉ định tham số dạng T chỉ có thể xảy ra trong điểm ra của giao ước, nếu không, sẽ nhận được lỗi biên lập. Đổi lại cho sự giới hạn này, giao ước IEnumerable trở thành một giao ước có tham số dạng đồng biến ở điểm giữ chỗ , có nghĩa là IEnumerable có thể coi là IEnumerable nếu X có định nghĩa dùng để chuyển hóa dạng.

Chức năng này rất hữu dụng cho nhiều hàm của LINQ, sẽ được hướng dẫn trong chương kế tiếp.

Dạng nghịch biến (contra-variance)

Một giao ước tập hợp chung mẫu cũng có thể có tham số dạng thuộc dạng nghịch biến. Tham số dạng thuộc dạng nghịch biến được định nghĩa với chỉnh từ in, như sau:

Code:
public interface IComparer { public int Compare(T trái, T phải); }

Giao ước chung mẫu, hoặc uỷ nhiệm chung mẫu, còn có thể có những tham số dạng thuộc dạng đồng biến và nghịch biến, như sau:

Code:
public delegate TResult Func(TArg arg);

Giới hạn

Tham số dạng khả biến chỉ có thể định nghĩa cho giao ước và uỷ nhiệm, và dạng khả biến chỉ có thể áp dụng cho những lớp đối tượng tham chiếu có hổ trợ chuyển hóa dạng. Chẳng hạn như chuyển hóa dạng giữa NhanVien và NhanCong, hoặc NhanCong qua Object. Từ int, hoặc double qua object chỉ là đóng gói, không phải là chuyển dạng, vì int và double không phải là những dạng tham chiếu, mà là những dạng có giá trị thực.

Mã nguồn mẫu

Dưới đây là nguyên văn bản mã nguồn mẫu, với Exel và Word được dùng để khởi tạo 2 đối tượng năng động. Sau đó, là những thao tác xử lý trên 2 đối tượng. Không có gì đặc biệt để phải lý giải, ngoài mục đích trình bày những chức năng mới của C# 4.0(dễ đọc, dễ hiểu hơn những cú pháp dùng COM trong những phiên bản trước).

Code:
using System; using System.Diagnostics;
using System.Linq;
using Excel = Microsoft.Office.Interop.Excel;
using Word = Microsoft.Office.Interop.Word;

class Program {
static void Main(string[] args) {
var excel = new Excel.Application();
excel.Visible = true;
excel.Workbooks.Add(); // tham số tùy chọn không được đưa qua
excel.Cells[1, 1].Value = "Process Name"; // không cần ép dạng, vì Value là variance
excel.Cells[1, 2].Value = "Memory Usage"; //
var processes = Process.GetProcesses() .OrderByDescending(p => p.WorkingSet) .Take(10);
int i = 2;
foreach (var p in processes) {
excel.Cells[i, 1].Value = p.ProcessName; // không cần ép dạng
excel.Cells[i, 2].Value = p.WorkingSet; // không cần ép dạng
i++;
}
Excel.Range range = excel.Cells[1, 1]; // không cần ép dạng
Excel.Chart chart = excel.ActiveWorkbook.Charts. Add(After: excel.ActiveSheet); // dùng tham số tên và tham số tuỳ chọn
chart.ChartWizard(Source: range.CurrentRegion, Title: "Memory Usage in " + Environment.MachineName); //tham số tên (Title) và tùy chọn
chart.ChartStyle = 45;
chart.CopyPicture(Excel.XlPictureAppearance.xlScreen, Excel.XlCopyPictureFormat.xlBitmap, Excel.XlPictureAppearance.xlScreen);
var word = new Word.Application();
word.Visible = true;
word.Documents.Add();
word.Selection.Paste();
}

Mar 16, 2010

Sử lý đệ quy trong SQL Server

Hôm nay làm môt tut về đệ qui trong SQL server. Trong lập trình thông thường bạn sẽ phải sử lý nhiều tình huống đề quy, nhưng ít khi nó thể hiện rõ tính chất đệ quy bởi nó chỉ là vòng lặp dạng for hoặc while. Và thực ra việc thiết kế giải thuật người ta cũng cố gắng đề giải đệ quy hoặc khử đệ quy để bảo đảm cấu trúc bộ nhớ của trương trình cũng như là cho code dễ hiểu.
Nhưng không phải lúc nào như lý thuyết cũng là đúng, trong một số tình huống cụ thể cách đệ quy chở nên hiệu quả ngắn ngọn và tối ưu hơn cách viết thông thường. Vậy bài viết này hướng dẫn bạn đệ quy trong DB.

Đệ quy để làm gì ? Với một business phức tạp và sử lý trên một cấu trúc cây đa cấp bạn sẽ mắc phải vấn đề rác rối về hiệu xuất của hệ thống khi quyết định sử lý tất cả trên tầng business. Chính vị vậy bạn cần sử lý một số các nghiệp vụ cụ thể trong DB nhằm tăng tốc cho hệ thống của mình. Đây chính là mảnh đất mà chúng ta khai thác...

Giả sử bạn có một cây đa cấp chông nó như thế này.


Khi đó trong DB bạn sẽ có một cấu trúc như thế này cho cái cây đó

và việc sử lý trên cây sẽ vô cùng rác rối với mỗi một node bạn phải kiểm tra xem nó là có con không ? cha nó là ai ? anh chị em nó là gì ? ....
ở đây tôi chỉ viết một hàm trong DB sql 2005, với mục đích nhận vào một node id và trả về môt bảng các node id con cháu nêu có.

code here.

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[udfNodeChirent]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [dbo].[udfNodeChirent]
GO

CREATE FUNCTION [dbo].[udfNodeChirent]
--======================================
--created by : linhdkl
--created date : 16/03/2010
--======================================

(
@parentID int
)
RETURNS @tbl TABLE (id int,valu int)
WITH EXECUTE AS CALLER
AS
begin
if @parentID > 0
begin
declare @tempCount int
declare @count int
set @count = 0
select @count = count(id)from tree where parentNodeid = @parentID
if(@count > 0)
begin
insert @tbl(id,valu) select ROW_NUMBER() over( order by ID),id
from tree
where parentNodeid = @parentID
declare @row int
set @row = 1
while @row <= @count
begin
select @tempCount = count(id) from @tbl
select @parentID = valu from @tbl where id = @row
insert @tbl(id,valu) select ROW_NUMBER() over( order by ID) + @tempCount,valu
from dbo.udfNodeChirent(@parentID)
set @row = @row +1
end
end
end
return
end
GO


Ok như vậy mình đã có cái func này và đây là kết quả.

select * from dbo.udfNodeChirent(47)
nó sẽ có kết quả là :

id valu
----------- -----------
1 72
2 99
3 100
4 73
5 74
6 95
7 105
8 106
9 75
10 76
11 102
12 103
13 104
14 107
15 101

(15 row(s) affected)

cái id chính là số thứ tự và valu là id của các con, cháu, chắt của thằng node 47.

Tuy nhiên cũng xin nói thêm là đây chỉ là cách sử lý dựa trên hệ thống đã có sẵn, tức là việc này chỉ cải thiện tình trạng một cách miễn cưỡng. Nếu một hệ thống đc thiết kế tốt, việc sử lý này sẽ sử dụng một danh sách liên kết và sử lý phi tuyến tính sẽ nhanh hơn rất nhiều. Tuy nhiên giá trị của giải thuật đệ qui vẫn tồn tại trong bất kỳ trường hợp nào.

../..


Feb 18, 2010

Tìm hiểu Objective - C phần 3

tiếp theo phần 2

Kiểu id
id trong ObC gần tương tự như void* trong C. bạn không cần phải biết rõ kiểu của object khi bạn gọi phương thức trong ObC điều này hoàn toàn khác với C++ bơi đơn giản khi gọi phương thức cũng giống như bạn truyền thông điệp trong ObC. Nếu đối tượng nó có phương thức thì sẽ đáp lại thông điệp mà bạn truyền (gọi phương thức) và phương thức đc gọi. Cũng nguy hiểm đây chứ .. :(


Ép kiểu động.
những phương thức dưới đây dùng để kiểm tra kiểu.

- (BOOL) isKindOfClass: classObj >> đối tượng là hậu duệ hoặc thể hiện của classObj
- (BOOL) isMemberOfClass: classObj >> là một thành phần của objClass
- (BOOL) respondsToSelector: selector >> đối tượng có phương thức bởi selector
+ (BOOL) instancesRespondToSelector: selector >> đối tượng đc tạo bởi lớp có đáp ứng selector
- (id) performSelector: selector >> triệu gọi chính sách selector trên đối tượng.


Constructors - hàm khỏi tạo:
Vấn đề là với một lớp thì hàm khởi tạo dùng để sinh đối tượng và cũng là chỗ để tư duy về hàm hủy và cách thức lưu trong bộ nhớ của đối tượng. Về vấn đề hủy đối tượng ta sẽ có một phần riêng và nó hoàn toàn khác biệt với việc viết hàm hủy trong C++ và các ngôn ngữ khác. Tất nhiên không có gì là không thể viết khi bạn đã hiểu rõ và thông thạo ngôn ngữ. Và hẳn nhiên bạn có thể quên hết những luật về khởi tạo đối tượng hàm tạo và hàm hủy của C++ vơi ObC bạn hoàn toàn có thể tự mình chế biến những hàm đó theo ý thích và cũng không có quy luật gì về tên tuổi của hàm, tuy nhiên theo thoi quen truyền thông để giúp style - code chở nên sáng sủa nên dùng bằng các từ như init hoặc tương tự... để định nghĩa hàm khởi tạo


Fraction.h
...
-(Fraction*) initWithNumerator: (int) n denominator: (int) d;
...



Fraction.m
...
-(Fraction*) initWithNumerator: (int) n denominator: (int) d {
self = [super init];

if ( self ) {
[self setNumerator: n andDenominator: d];
}

return self;
}
...



main.m
#import
#import "Fraction.h"

int main( int argc, const char *argv[] ) {
// create a new instance
Fraction *frac = [[Fraction alloc] init];
Fraction *frac2 = [[Fraction alloc] init];
Fraction *frac3 = [[Fraction alloc] initWithNumerator: 3 denominator: 10];

// set the values
[frac setNumerator: 1];
[frac setDenominator: 3];

// combined set
[frac2 setNumerator: 1 andDenominator: 5];

// print it
printf( "The fraction is: " );
[frac print];
printf( "\n" );

printf( "Fraction 2 is: " );
[frac2 print];
printf( "\n" );

printf( "Fraction 3 is: " );
[frac3 print];
printf( "\n" );

// free memory
[frac release];
[frac2 release];
[frac3 release];

return 0;
}

- Từ khóa supper để tham chiếu tới lớp cha.
- Từ khóa self tác dụng tương đương như this trong C++. (chính bản thân đang thể hiện của lớp - object hiện tại)
- Kết thúc hàm khởi tạo (init) sẽ trả về chính đối tượng dc tạo ra thông qua từ khóa self.
- Mặc định trong ObC hàm khỏi tạo là - (id) init;
- Trong ObC hàm khởi tạo chỉ có ý nghĩa về mặt tư duy, nó không đc đối sử đặc biết giống như C++.


Đa hình.
có lẽ với những trình bày ở trên phần nào giúp bạn mường tượng ra dc cơ chế đa hình của ObC. phần này chỉ là viết thêm nhằm củng cố một số những điểm sau đây.
1. Trong ObC không có từ khóa virtual và thực sự là không cần thiết vì nó sẽ không tạo ra những thứ quá phức tạp giống như C++ vì việc phủ quyết hàm trong ObC là phủ quyết trắng chợn không liên quan gì tới sự kế thừa. nếu 2 hàm giống hệt nhau ở 2 lớp quan hệ cha con thì cũng chẳng sao cả. cũng cần nói thêm là ObC là đơn kế thừa.
2. Quá trình tạo mối liên hệ giữa thể hiện của ObC và phương thức sẽ đc gọi là thời điểm run-time. Điểu này hoàn toàn có ý nghĩa nếu bạn gọi một phương thức mà bản thân đối tượng không có cũng không có lỗi gì. Lỗi chỉ xảy ra khi lời gọi đó dc thực hiện. Tuy nhiên ban cũng dc cung cấp những cơ chế để kiểm soát việc này. đây cũng là một đặc tính Run-Time của ObC nếu bạn quan tâm có thể tìm kiếm thông tin từ việc chuyển tiếp thông điệp (forward) tới một đối tượng khác.


Quản ly bộ nhớ.
ObC có 2 lựa chọn cho việc quản lý bộ nhớ. Thông thường bộ nhớ dc quản lý bởi lập trình viên, ObC có trình biên dịch chỉ thị nhứ "release", "retain", "autorelease" là những chỉ thị hỗ chợ lập trình viên mạnh mẽ trong việc quản lý bộ nhớ.
ObC sử dụng một tham chiếu đếm để dò tìm ra những thay đổi trên một đối tượng. Biến đếm này sẽ tăng lên một khi đối tượng dc cấp phát bộ nhớ bằng phương thức alloc, biến đếm này sẽ giảm đi một khi đối tượng dc giải phóng bằng phương thức dealloc. Như vậy nguyên lý cấp phát và duy trì bộ nhớ của đối tượng trong ObC dc sử dụng thông qua phương thức alloc và dealloc.

Mặt khác tiện ích khác từ kiểu dữ liệu nil đã nói ở trên đó việc giải phóng bộ nhơ. Trong ngữ cảnh một đối tượng của bạn là bao gồm nhiều những đối tượng khác. những đối tượng khác đó có thể đã dc giải phóng hoặc chưa. như thế bạn sẽ thực hiện lời gọi dealloc trên tập đối tượng mà bạn có, nếu con thì nó sẽ thực hiện giải phóng trong trường hợp bằng nil cũng ok :D không vấn đề gì (no error) vì nil cũng có thể truyền thông điệp.
hãy xem ví dụ

# AddressCard.h

#import
#import

@interface AddressCard: NSObject {
NSString *first;
NSString *last;
NSString *email;
}

-(AddressCard*) initWithFirst: (NSString*) f
last: (NSString*) l
email: (NSString*) e;
-(NSString*) first;
-(NSString*) last;
-(NSString*) email;
-(void) setFirst: (NSString*) f;
-(void) setLast: (NSString*) l;
-(void) setEmail: (NSString*) e;
-(void) setFirst: (NSString*) f
last: (NSString*) l
email: (NSString*) e;
-(void) setFirst: (NSString*) f last: (NSString*) l;
-(void) print;
@end

# AddressCard.m

#import "AddressCard.h"
#import

@implementation AddressCard
-(AddressCard*) initWithFirst: (NSString*) f
last: (NSString*) l
email: (NSString*) e {
self = [super init];

if ( self ) {
[self setFirst: f last: l email: e];
}

return self;
}

-(NSString*) first {
return first;
}

-(NSString*) last {
return last;
}

-(NSString*) email {
return email;
}

-(void) setFirst: (NSString*) f {
[f retain];
[first release];
first = f;
}

-(void) setLast: (NSString*) l {
[l retain];
[last release];
last = l;
}

-(void) setEmail: (NSString*) e {
[e retain];
[email release];
email = e;
}

-(void) setFirst: (NSString*) f
last: (NSString*) l
email: (NSString*) e {
[self setFirst: f];
[self setLast: l];
[self setEmail: e];
}

-(void) setFirst: (NSString*) f last: (NSString*) l {
[self setFirst: f];
[self setLast: l];
}

-(void) print {
printf( "%s %s <%s>", [first cString],
[last cString],
[email cString] );
}

-(void) dealloc {
[first release];
[last release];
[email release];

[super dealloc];
}
@end

# main.m

#import "AddressCard.h"
#import
#import

int main( int argc, const char *argv[] ) {
NSString *first =[[NSString alloc] initWithCString: "Tom"];
NSString *last = [[NSString alloc] initWithCString: "Jones"];
NSString *email = [[NSString alloc] initWithCString: "tom@jones.com"];
AddressCard *tom = [[AddressCard alloc] initWithFirst: first
last: last
email: email];

// we're done with the strings, so we must dealloc them
[first release];
[last release];
[email release];

// print to show the retain count
printf( "Retain count: %i\n", [[tom first] retainCount] );
[tom print];
printf( "\n" );
// free memory
[tom release];

return 0;
}

# output

Retain count: 1
Tom Jones

Mặt khác ObC cũng cung cấp một cớ chế thông minh thường thường trong việc bạn gọi và sử dụng đối tượng mà không phải quan tâm lo lắng đến việc cấp phát và giải phóng bộ nhớ đó là cơ chế NSAutoreleasePool. Để dùng dc cơ chế này bạn chỉ việc nhớ 2 điều kẹp đoạn code mà bạn muốn kiểm soát vào trong giữa NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init] và [pool release]. Nguyên lý của đồng chí này cũng giống như lời gọi hàm vì thế bạn hoàn toàn có thể sử dụng lồng nhau và sự đóng mở hợp lý (giống như thẻ đóng và mở của XML đó) tự nhiên ObC sẽ đẩy các lời gọi pool sau xuống stack và đặt pool mới trên cùng sau đó nhét các object dc tạo ra trong lòng nó vào cái pool vừa mới tạo nếu song thì giải phóng rồi lại đẩy tiếp thằng pool ở dưới lên cứ thế... kinh chưa :).



Tổng kết:

Đây không phải là một ngôn ngữ compile và là ngôn ngữ run-time. Cho nên trong quá trình code yêu tố này ảnh hưởng rất lớn tới chương trình của bạn. Các đặc điểm như ép kiểu. Đa hình... sẽ rất mềm dẻo.


nội dung bài viết và vi dụ tham khảo tại:


các phần trước.


../..

Feb 17, 2010

Tìm hiểu Objective - C phần 2

tiếp theo phần 1

Exception và handler.
Ngôn ngữ cũng hỗ chợ các cấu trúc try - catch - throw - finally giống như ngôn C++ @try - @catch - @throw - @finally cách thức sử dụng cũng hoàn toàn tương tự.


Categories
Là đặc điểm nếu bạn muốn mở rộng lớp bằng cách thêm mới vào lớp một phương thức. Khi bạn làm việc quen với OOP thì bạn sẽ thấy đây là một trong những thuộc tính vô cùng hữu ích của Objective C, kể cả ngay khi bạn không có mã nguồn của lớp nhưng bạn vẫn hoàn toàn có thể thêm phương thức cho lớp như thường thông qua thuộc tính này. Đặc điểm này làm giảm đi đáng kể sự kế thừa phức tạp trong C++ khi việc kế thừa chỉ để phục vụ cho việc thêm mới một phương thức. Mặt khăc việc chia mã nguồn trên nhiều files cũng giúp ích đáng kể trong việc phát triên.

#import "Fraction.h"

@interface Fraction (Math)
-(Fraction*) add: (Fraction*) f;
-(Fraction*) mul: (Fraction*) f;
-(Fraction*) div: (Fraction*) f;
-(Fraction*) sub: (Fraction*) f;
@end

File thực thi.

#import "FractionMath.h"

@implementation Fraction (Math)
-(Fraction*) add: (Fraction*) f {
return [[Fraction alloc] initWithNumerator: numerator * [f denominator] +
denominator * [f numerator]
denominator: denominator * [f denominator]];
}

-(Fraction*) mul: (Fraction*) f {
return [[Fraction alloc] initWithNumerator: numerator * [f numerator]
denominator: denominator * [f denominator]];

}

-(Fraction*) div: (Fraction*) f {
return [[Fraction alloc] initWithNumerator: numerator * [f denominator]
denominator: denominator * [f numerator]];
}

-(Fraction*) sub: (Fraction*) f {
return [[Fraction alloc] initWithNumerator: numerator * [f denominator] -
denominator * [f numerator]
denominator: denominator * [f denominator]];
}
@end

- Tên của category phải là duy nhất
- Có thể thêm bao nhiêu lần mở rộng lơp từ category là không giới hạn nhưng với tên là duy nhất.
- Thông thể bổ xung biến thành phần bằng category.
- Có thể sử dụng category để tạo ra các phương thức private. Nếu cần.

MyClass.h
#import

@interface MyClass: NSObject
-(void) publicMethod;
@end


MyClass.m
#import "MyClass.h"
#import

@implementation MyClass
-(void) publicMethod {
printf( "public method\n" );
}
@end

// private methods
@interface MyClass (Private)
-(void) privateMethod;
@end

@implementation MyClass (Private)
-(void) privateMethod {
printf( "private method\n" );
}
@end


main.m
#import "MyClass.h"

int main( int argc, const char *argv[] ) {
MyClass *obj = [[MyClass alloc] init];

// this compiles
[obj publicMethod];

// this throws errors when compiling
//[obj privateMethod];

// free memory
[obj release];
return 0;
}

cái này thật thú vị phải không, thực ra đây là một hệ quả trực tiếp từ đăc tính run-time của Objective C.


Protocals: Giao diện.
Đây hoàn toàn tương đồng với khái miện lớp ảo trong C++ hoặc gọi là giao diện trong C# và Java. Bản thân @protocals không có sự thực thi. Nếu lớp nào cam kết thực thi nó thì trong phần thực thi sẽ implement các phương thức mà protocals khai báo.

@protocol Printing
-(void) print;
@end
Fraction.h
#import
#import "Printing.h"

@interface Fraction: NSObject {
int numerator;
int denominator;
}

-(Fraction*) initWithNumerator: (int) n denominator: (int) d;
-(void) setNumerator: (int) d;
-(void) setDenominator: (int) d;
-(void) setNumerator: (int) n andDenominator: (int) d;
-(int) numerator;
-(int) denominator;
@end


Fraction.m
#import "Fraction.h"
#import

@implementation Fraction
-(Fraction*) initWithNumerator: (int) n denominator: (int) d {
self = [super init];

if ( self ) {
[self setNumerator: n andDenominator: d];
}

return self;
}

-(void) print {
printf( "%i/%i", numerator, denominator );
}

-(void) setNumerator: (int) n {
numerator = n;
}

-(void) setDenominator: (int) d {
denominator = d;
}

-(void) setNumerator: (int) n andDenominator: (int) d {
numerator = n;
denominator = d;
}

-(int) denominator {
return denominator;
}

-(int) numerator {
return numerator;
}

-(Fraction*) copyWithZone: (NSZone*) zone {
return [[Fraction allocWithZone: zone] initWithNumerator: numerator
denominator: denominator];
}
@end


Complex.h
#import
#import "Printing.h"

@interface Complex: NSObject {
double real;
double imaginary;
}

-(Complex*) initWithReal: (double) r andImaginary: (double) i;
-(void) setReal: (double) r;
-(void) setImaginary: (double) i;
-(void) setReal: (double) r andImaginary: (double) i;
-(double) real;
-(double) imaginary;
@end


Complex.m
#import "Complex.h"
#import

@implementation Complex
-(Complex*) initWithReal: (double) r andImaginary: (double) i {
self = [super init];

if ( self ) {
[self setReal: r andImaginary: i];
}

return self;
}

-(void) setReal: (double) r {
real = r;
}

-(void) setImaginary: (double) i {
imaginary = i;
}

-(void) setReal: (double) r andImaginary: (double) i {
real = r;
imaginary = i;
}

-(double) real {
return real;
}

-(double) imaginary {
return imaginary;
}

-(void) print {
printf( "%_f + %_fi", real, imaginary );
}
@end


main.m
#import
#import "Fraction.h"
#import "Complex.h"

int main( int argc, const char *argv[] ) {
// create a new instance
Fraction *frac = [[Fraction alloc] initWithNumerator: 3 denominator: 10];
Complex *comp = [[Complex alloc] initWithReal: 5 andImaginary: 15];
id printable;
id copyPrintable;

// print it
printable = frac;
printf( "The fraction is: " );
[printable print];
printf( "\n" );

// print complex
printable = comp;
printf( "The complex number is: " );
[printable print];
printf( "\n" );

// this compiles because Fraction comforms to both Printing and NSCopyable
copyPrintable = frac;

// this doesn't compile because Complex only conforms to Printing
//copyPrintable = comp;

// test conformance

// true
if ( [frac conformsToProtocol: @protocol( NSCopying )] == YES ) {
printf( "Fraction conforms to NSCopying\n" );
}

// false
if ( [comp conformsToProtocol: @protocol( NSCopying )] == YES ) {
printf( "Complex conforms to NSCopying\n" );
}

// free memory
[frac release];
[comp release];

return 0;
}



Properties
Thuộc tính gần như bất cứ một ngôn ngữ mới hiện đại nào cũng hỗ chợ khái niệm này, đây là một khái niệm bảo toàn tính đóng gói của tư tưởng OOP.
Đối vơi ngôn ngữ ObC có mốt số những hỗ chợ đặc biệt hơn một chút bạn khai báo sử dụng bằng @properties cũng giống như những ngôn ngữ khác khi bạn sử dụng thuộc tính với ObC bạn sẽ có 2 lựa chọn là @synthesize và @dynamic, với lựa chọn là @synthesize thì mặc nhiên trình biên dịch sẽ giúp bạn sinh ra các phương thức set và get trên thuộc tính. nhưng nếu bạn lựa chọn là @dynamic thì mọi việc bạn phải tự làm lấy.
hãy xem code
#import

@interface Photo : NSObject {
NSString* caption;
NSString* photographer;
}
- (NSString*) caption;
- (NSString*) photographer;

- (void) setCaption: (NSString*)input;
- (void) setPhotographer: (NSString*)input;

@end


#import

@interface Photo : NSObject {
NSString* caption;
NSString* photographer;
}
@property (retain) NSString* caption;
@property (retain) NSString* photographer;

@end



Feb 10, 2010

Tìm hiểu Objective - C

Cũng chẳng biết lý do nào cho mình chở thành một thằng dev-er ....

Hôm nay tìm hiểu về dev ứng dụng cho em IPhone nên là làm một tút về Objective - C chú này khá là mền dẻo và linh động trong sử lý nghe nói còn dẻo hơn cả C++ nữa chứ.

1. Một vài dòng về lịch sự ra đời và sự phát triển.
Cái gì cũng vậy ... mà hơn hết mình là dân Châu Á nên làm việc phải có trước có sau có cội có nguồn - ấy vì thế mà đừng vội đọc phần sau ngay mà hay quan tâm một chút tới cội nguồn của thàng Objective - C này.

Lịch sử ra đời
The wiky thì Bard Cox và Tom Love (không biết có thằng cha này không nhưng thấy wiki nó nói thì mình cũng đưa ra đây chắc lão Tom Love này cũng có chút ít công sức) thuộc Stepstone là cha đẻ của Objective - C. Ngôn ngữ này đc giới thiệu năm 1981 và chúng ta cũng nhớ rằng thập niên 80s của thế kỷ trước là sự lên ngôi của khái niệm lập trình OOP cũng là giai đoạn cực thịnh của sự ra đời các ngôn ngữ OOP trên nên C. Tiếp tục hoàn thiện trong vài năm đến 1986 Cox chính thức ấn hành chuẩn của Objective - C trong các cuốn sách Object-Oriented Programming, An Evolutionary Approach.

Sự kế tiếp của Steve Jobs
Cái tên này đã chở nên qua nổi tiếng từ cuộc đời ông cho đến sự nghiệp lẫy lừng và cả việc ông làm điên đảo cộng đồng IT thế giới cho đến chính bạn (chẳng phải bạn cũng đang diên đảo vì IPhone đây !_! )
Khi bi out khỏi Apple, năm 1988 Steve Jobs đã mua lại bản quyên của Obejctive - C từ Stepstone để viết cho ứng dụng phần cứng của mình. vọi là NeXTstep hay còn gọi là OpenStep công ty lúc này của Jobs là NeXT.
Cho đến 1996 khi Apple mua lại NeXT thì họ tiếp tục sử dụng công nghệ OpenStep để phát triên hệ điều hành Mac của họ và xây dựng một loạt công cụ XCode, Interface Builder .. và các Cocoa API ra đời...
Đến giờ thì đã hiểu là tại sao lại là Objective - C chứ không phải bất cứ ngôn ngữ nào khác để build các App trên nền Apples.


2. Tìm hiểu ngôn ngữ Ob-c

Đặc điểm cơ bản.
- Là ngôn ngữ hướng đối tượng
- Mở rộng từ C
- Nhẹ nhàng (không VM - không quá thực tạp với friend virtuals với template với ....)
- Mềm dẻo (mở rộng từ C nên bạn có thể dùng C thuần cấu trúc ngoài ra đây là ngôn ngữ run-time)
- Reflection (có hỗ chợ)
- nil thay thế cho NULL trong C, bởi vì bạn có thể gửi thông điệp cho nil, nhưng không thể làm như vậy với NULL.
- BOOL có 2 giá trị là YES và NO chứ không phải là true và false nữa.
- Khái niệm methods và message đc sử dụng mang ý nghĩa như nhau đối với ObC theo đó message có những thuộc tính đặc biệt. Mọto message có thể chuyền động từ obj tới một obj khác. Việc gọi thông điệp trên một obj không có nghĩa là obj đó sẽ thực hiện message nó có thể chuyển tiếp tới một obj khác chưa biết trước tóm lại có khả năng đáp trả thông điệp không trực tiệp thì gián tiếp.

Khi làm việc với Objective C bạn cần chú ý là bởi vì nó dc base trên nền của C cho nên việc bạn sử dụng cú pháp C chộn lẫn với cú pháp chính thống của Objective C là hoàn toàn chấp nhận, tuy nhìn có vẻ hơi củ chuối.


Phương thưc.
Cách khai báo phương thức trong Objective - C
Không tham số :
<(kiểu trả về)>

Có tham số:
<(kiểu trả về)> :<(kiểu)> :<(kiểu)> ;

Lời gọi phương thức:
không trả về: [<đối tượng> ];
[<đối tượng> :<(kiểu)> ];
[<đối tượng> :<(kiểu)> :<(kiểu)> ];

Trả về kết quả: = [<đối tượng> ];
= [<đối tượng> :<(kiểu)> :<(kiểu)> ];



Lớp và đối tượng.
Ob-C sử dụng khái niệm Interface và Implementation để phân biêt file Header và file Source của C (*.h và *.c) một lớp trong ObC định nghĩa là trên một giao diện (.h) còn phần thực thi trên file .m các bạn chú ý là m vì nó khác với C và C++.

@interface:

#import @interface Fraction: NSObject {
int numerator;
@private
int denominator;
}
-(void) print;
-(void) setNumerator: (int) n;
-(void) setDenominator: (int) d;
-(int) numerator;
-(int) denominator;

@end

và đây là phần thực thi.
@implementation

#import "Fraction.h"
@implementation Fraction

-(void) print {
printf( "%i/%i", numerator, denominator );
}

-(void) setNumerator: (int) n {
numerator = n;
}

-(void) setDenominator: (int) d {
denominator = d;
}

-(int) denominator {
return denominator;
}

-(int) numerator {
return numerator;
}
@end

- Sử dụng #import để thay thế cho #include (đây là cơ chế thông minh hơn #include của C/C++ bạn chỉ phải thêm 1 lần thôi )
- ObC chỉ cho phép đơn kế thừa. Mặc định tất cả các lớp sẽ kế thừa từ NSObject.
- Cặp @.... và @end là cặp giới hạn phạm vi một lớp.
- Các thuộc tính dc khái báo trong cặp { ..... } và khai báo phương thức ở bên ngoài.
- Nếu phương thức bắt đâu bằng "+" có nghĩa nó là thuộc phạm vi lớp (static), còn nếu "-" thì nó ở phạm vi object.
- Các phạm vi truy xuất public,protected và private giống như C++ mặc định là protected.
- Các truy nhập phần tử cũng sử dụng toán tử "." đối với object và "->" nếu là con trỏ.
- không có các tầm vực truy xuất đối với phương thức (tức là trong ObC các phương thức có cùng một tầm vực là public)



Dec 8, 2009

Get Links From MediaFire

Là một người mê phim ảnh bạn sẽ không ít lần download film từ site MediaFire.com, có thể nói đây là một site hoàn toàn tuyện vời, tốc độ down nhanh kinh hồn và cho phép down nhiều file cùng lúc.
Nhưng cũng dở nếu phải thực hiện với từng link một.
minh đã viết một tool dùng để lấy tất cả link download và dùng với IDM để down về.

Download và sử dụng
download: getlinksMF
sử dụng yêu cầu bạn phải cài đặt .NET Framework (>=2.0). Nếu bạn dùng window 7 hoặc vista thì mặc nhiên bộ .NET framework này đã tích hợp trong windows của bạn bạn chỉ việc down về và chạy.

Nếu bạn không có IDM bạn có thể download từ đây
cài ra và thực hiện theo hướng dẫn crack trong file .rar

Bạn nào có hứng thú tìm hiểu thì mail tôi gửi code cho.

Giao diện trương trình



Sau khi bạn lấy được link bạn save ra thanh file .txt sau đó bạn import file này vào IDM để IDM down nó về.

và phần này hướng mình hướng dẫn sử dụng IDM để add link từ file .txt vào IDM.









Aug 30, 2009

Paging by currsor

Nhân cái sự ông bạn gửi cho một bài về kỹ thuật tìm kiếm và săp xếp ở đây. Hôm nay đẹp trời xin bàn xâu thêm một chút về vấn đề này và giới thiệu một kỹ thuật khác để paging nữa là sử dụng cursor để anh em tham khảo.

1. Nói về tìm kiếm.
Nếu bạn làm về tìm kiếm dữ liệu (chỉ nói trong môi trường SQL - Database). Điều đầu tiên bạn phải tính đến Index đây là một thuộc tính vô cùng mạnh mẽ giúp bạn tìm kiếm. Bên cạnh đó nếu gặp chở ngại về Index bạn phải sử dụng tiếp tới Full Text Search. nếu bạn không sử dụng những thuộc tính này của database thì ứng dụng của bạn sẽ đần ra khi bạn phải search khoảng 4 nghìn records. Index là một thuộc tính cổ điển của các hệ quản trị dữ liệu, Nhưng khi bạn Index trên một trường dữ liệu là TEXT thì độ dài không chế của trường này bị giới hạn và như thế INDEX không thể làm việc trên trường dữ liệu text dài. Hoặc nếu có thì cũng không hiệu quả. Nhưng đừng lo lắng vì bạn sẽ hoàn toàn thỏa mãn việc tìm kiếm text với Full Text Search. Một design tốt cho DB sẽ là tiền đề để bạn cải thiện hiệu năng của hệ thống cũng như việc sẽ phải thay đổi lại cấu trúc ... Design tốt rất quan trọng

2. Nói về con trỏ.
Có rất nhiều những tranh cãi nhau về kỹ thuật paging bằng con trỏ cũng như sử dụng subquery (con sp của ông bạn sử dụng subquery ) . Theo ý kiến riêng tôi thây rằng con trỏ nhanh hơn nhưng không an toàn. Nguy cơ là rất lớn khi bạn sử dụng con trỏ trong việc paging.

3. Paging by cursor - demo

CREATE PROCEDURE [dbo].[prc_Paging_Cursor] (
@
Tables varchar(1000),
@
PK nvarchar(100),
@
Sort nvarchar(200) = NULL,
@
PageNumber int = 1,
@
PageSize int = 10,
@
Fields nvarchar(1000) = '*',
@
Filter nvarchar(1000) = NULL,
@
Group varchar(1000) = NULL)
AS

/*Find the @PK type*/
DECLARE @PKTable varchar(100)
DECLARE @
PKName varchar(100)
DECLARE @
type varchar(100)
DECLARE @
prec int

IF CHARINDEX('.', @PK) > 0
BEGIN
SET
@PKTable = SUBSTRING(@PK, 0, CHARINDEX('.',@PK))
SET @PKName = SUBSTRING(@PK, CHARINDEX('.',@PK) + 1, LEN(@PK))
END
ELSE
BEGIN
SET
@PKTable = @Tables
SET
@PKName = @PK
END

SELECT
@type=t.name, @prec=c.prec
FROM sysobjects o
JOIN syscolumns c on o
.id=c.id
JOIN systypes t on c
.xusertype=t.xusertype
WHERE o
.name = @PKTable AND c.name = @PKName

IF CHARINDEX('char', @type) > 0
SET
@type = @type + '(' + CAST(@prec AS varchar) + ')'

DECLARE @strPageSize varchar(50)
DECLARE @
strStartRow varchar(50)
DECLARE @
strFilter nvarchar(1000)
DECLARE @
strGroup varchar(1000)

/*Default Sorting*/
IF @Sort IS NULL OR @Sort = ''
SET @Sort = @PK

/*Default Page Number*/
IF @PageNumber < 1
SET
@PageNumber = 1

/*Set paging variables.*/
SET @strPageSize = CAST(@PageSize AS varchar(50))
SET @strStartRow = CAST(((@PageNumber - 1)*@PageSize + 1) AS varchar(50))

/*Set filter & group variables.*/
IF @Filter IS NOT NULL AND @Filter != ''
SET @strFilter = ' WHERE ' + @Filter + ' '
ELSE
SET @strFilter = ''
IF @Group IS NOT NULL AND @Group != ''
SET @strGroup = ' GROUP BY ' + @Group + ' '
ELSE
SET @strGroup = ''

--SET @type='uniqueidentifier'
/*Execute dynamic query*/

EXEC('
DECLARE @PageSize int
SET @PageSize = '
+ @strPageSize + '

DECLARE @PK '
+ @type + '
DECLARE @tblPK TABLE
(
PK '
+ @type + ' NOT NULL PRIMARY KEY
)

DECLARE PagingCursor CURSOR DYNAMIC READ_ONLY FOR
SELECT '
+ @PK + ' FROM ' + @Tables + @strFilter + ' ' + @strGroup + ' ORDER BY ' + @Sort + '

OPEN PagingCursor
FETCH RELATIVE '
+ @strStartRow + ' FROM PagingCursor INTO @PK

SET NOCOUNT ON

WHILE @PageSize > 0 AND @@FETCH_STATUS = 0
BEGIN
INSERT @tblPK (PK) VALUES (@PK)
FETCH NEXT FROM PagingCursor INTO @PK
SET @PageSize = @PageSize - 1
END

CLOSE PagingCursor
DEALLOCATE PagingCursor

SELECT '
+ @Fields + ' FROM ' + @Tables + ' JOIN @tblPK tblPK ON ' + @PK + ' = tblPK.PK ' + @strFilter + ' ' + @strGroup + ' ORDER BY ' + @Sort
)

Aug 28, 2009

Kỹ thuật phân trang trong Database

Phần này của ông bạn tôi viết, gửi cho tôi theo kiểu khuyến mại. Đôi khi mình cũng lười thế là dùng luôn. Nhưng đọc kỹ lại phát hiện một số những điểm nên cài tiến.
1. Không sử dụng câu lệnh CREATE TABLE như trong này.
mà nên dùng DECLARE @tblTemp TABLE(id INT PRIMARY KEY, ...)

2. Không nên khai báo con trỏ trong SQL theo kiểu như thế này.
mà nên khai báo thế này thêm các từ khóa như readonly,...

bên cạnh đó cũng còn một kỹ thuật phân trang khác bằng cách sử dụng con trỏ. Tôi sẽ giới thiệu trong bài sau.

-------------------------------------------
if
exists (select name from sysobjects where name = 'GetManyCUS_ResultBySearch')
drop proc GetManyCUS_ResultBySearch
go

create procedure GetManyCUS_ResultBySearch
@Keyword nvarchar(100),
@
TypeID char(5),
@
PageSize int,
@
PageNumber int,
@
ItemCount int OUT

as
begin

declare @sqlNewsSelect nvarchar(max),
@
sqlDocumentSelect nvarchar(max),
@
sqlProjectFDISelect nvarchar(max),
@
sqlProjectODASelect nvarchar(max),
@
sqlNewsTerm nvarchar(max),
@
sqlDocumentTerm nvarchar(max),
@
sqlProjectFDITerm nvarchar(max),
@
sqlProjectODATerm nvarchar(max)

--------------------------------------------------------------------
/*Cac bieu thuc select*/
--------------------------------------------------------------------
set @sqlNewsSelect = '
select
a.NewsTitle as ''Title'',
cast(a.NewsDescription as nvarchar(250)) as ''Description'',
'''' as ''PathFile'',
b.TypeID as ''TypeID''
from CMS_News a
inner join CMS_Category b on a.CategoryID = b.CategoryID
where b.TypeID = ''news''
'
set @sqlDocumentSelect = '
select
a.DocumentName as ''Title'',
cast(a.DocumentDescription as nvarchar(250)) as ''Description'',
a.DocumentFilePath as ''PathFile'',
b.TypeID as ''TypeID''
from CMS_Document a
inner join CMS_Category b on a.CategoryID = b.CategoryID
where b.TypeID = ''docum''
'
set @sqlProjectFDISelect = '
select
a.ProjectFDIName as ''Title'',
cast(a.FDIDetailContent as nvarchar(250)) as ''Description'',
a.FDIDocumentPath as ''PathFile'',
b.TypeID as ''TypeID''
from CMS_ProjectFDI a
inner join CMS_Category b on a.CategoryID = b.CategoryID
where b.TypeID = ''proje''
'
set @sqlProjectODASelect = '
select
a.ProjectODAName as ''Title'',
cast(a.ODADetailContent as nvarchar(250)) as ''Description'',
a.ODADocumentPath as ''PathFile'',
b.TypeID as ''TypeID''
from CMS_ProjectODA a
inner join CMS_Category b on a.CategoryID = b.CategoryID
where b.TypeID = ''proje''
'
--------------------------------------------------------------------
/*Phan tich chuoi keyword dau vao thanh cac keyword nho*/
--------------------------------------------------------------------

set @sqlNewsTerm = ' 1 != 1'
set @sqlDocumentTerm = ' 1 != 1'
set @sqlProjectFDITerm = ' 1 != 1'
set @sqlProjectODATerm = ' 1 != 1'

create table #Keyword(Keyword nvarchar(100))
declare @sep nvarchar(10)
set @sep = ' '
declare @keywordTemp nvarchar(500)
set @keywordTemp = replace(LTRIM(RTRIM(@Keyword))+' ','''','''''')
while(
CHARINDEX(@sep + @sep, @keywordTemp COLLATE Latin1_General_CS_AS) > 0)
set @keywordTemp = replace(@keywordTemp, @sep + @sep, @sep)
declare @
indexBegin int
declare @indexEnd int
set
@indexBegin = 1
while(CHARINDEX ( @sep,@keywordTemp COLLATE Latin1_General_CI_AS, @indexBegin) > 0)--Latin1_General_CS_AS
begin
set
@indexEnd = CHARINDEX ( @sep,@keywordTemp COLLATE Latin1_General_CI_AS, @indexBegin)
insert into #Keyword values (SUBSTRING(@keywordTemp, @indexBegin, @indexEnd - @indexBegin))
set @indexBegin = @indexEnd + 1
end
declare @KeywordExec nvarchar(500)
declare
rm_cursor cursor for
select
Keyword
from
#Keyword
open rm_cursor
fetch next from rm_cursor into
@KeywordExec
while (@@FETCH_STATUS = 0)
begin
--------------------------------------------------------------------
/*Dua cac tu tim duoc trong chuoi de ghep thanh bieu thuc tim kiem*/
--------------------------------------------------------------------
set @KeywordExec = 'N''%' + @KeywordExec + '%'''
set @sqlNewsTerm = @sqlNewsTerm + ' or a.NewsTitle like ' + @KeywordExec
set
@sqlDocumentTerm = @sqlDocumentTerm + ' or a.DocumentName like ' + @KeywordExec
set
@sqlProjectFDITerm = @sqlProjectFDITerm + ' or a.ProjectFDIName like ' + @KeywordExec
set
@sqlProjectODATerm = @sqlProjectODATerm + ' or a.ProjectODAName like ' + @KeywordExec
fetch next from rm_cursor into
@KeywordExec
end
close rm_cursor
deallocate rm_cursor
drop table
#Keyword

declare @sql nvarchar(max)
set @sql = '
select
row_number() over( order by Title) as RowNumber,
Title,
Description,
PathFile,
TypeID
from ('
+ @sqlNewsSelect + ' and (' + @sqlNewsTerm + ')'
+ ' union '
+ @sqlDocumentSelect + ' and (' + @sqlDocumentTerm + ')'
+ ' union '
+ @sqlProjectFDISelect + ' and (' + @sqlProjectFDITerm + ')'
+ ' union '
+ @sqlProjectODASelect + ' and (' + @sqlProjectODATerm + ')'
+') as tblSelect'

insert into loghiep values(@sql)

declare @
sqlcount nvarchar(max)
set @sqlcount = 'select count(*) from ('+@sql+') as tbl_Result'
create table #ItemCount(ItemCount int)
insert into #ItemCount exec(@sqlcount)
set @ItemCount = (select top(1) ItemCount from #ItemCount)
drop table #ItemCount
declare @ItemMin int, @ItemMax int
set
@ItemMin = @PageSize * @PageNumber - @PageSize + 1
set
@ItemMax = @PageSize * @PageNumber + 1
if @ItemMin < 0 set @ItemMin = 0
if @ItemMax < 0 set @ItemMax = 0
set
@sql = 'select
Title,
Description,
PathFile,
TypeID
from ('
+@sql+') as tbl_Result where 1 = 1'
set @sql = @sql + ' and RowNumber >= ' + convert(varchar(10), @ItemMin)
set @sql = @sql + ' and RowNumber < ' + convert(varchar(10), @ItemMax)
exec(@sql)

end
go

grant execute on GetManyCUS_ResultBySearch to
public
go
 
Bạn có thể dùng bài viết của tôi tùy ý bạn nhưng vui lòng ghi lại rõ nguồn cung cấp
The world in a click_
Copyright © 2008 linhdkl