Professional Documents
Culture Documents
(CNdotNET-K36) -Bài Tập Chương 2 -Đinh Ngọc Điệp
(CNdotNET-K36) -Bài Tập Chương 2 -Đinh Ngọc Điệp
I. ASSEMBLIES
Assemblies là một phần cơ sở lập trình với .NET Framework. Assembly thực hiện
các chức năng sau:
Nó chứa mã thực thi CLR. Mã ngôn ngữ trung gian (MSIL) chứa trong một tập
tin thực thi di động (PE) sẽ không được thực thi nếu nó không có khai báo
assembly liên kết. Lưu ý assembly chỉ có một điểm bắt đầu (đây là:DllMain ,
WinMain , hoặc hàm Main).
Nó là dạng giới hạn bảo vệ. Một assembly là đơn vị mà cho phép yêu cầu và
chấp nhận.
Nó là dạng một kiểu giới hạn. Mỗi loại đặc tính bao gồm tên của assembly mà
nó cư trú. Một loại được gọi là MyType được tải trong phạm vi của một
assembly là không giống như là một loại gọi là MyType được tải trong phạm vi
assembly khác.
Nó là dạng giới hạn phạm vi tham khảo. Biểu thị của assembly chứa assembly
metadata được sử dụng để giải quyết các loại và đáp ứng yêu cầu tài nguyên.
Nó chỉ rõ các loại và tài nguyên được tiếp xúc bên ngoài assembly. Các biểu thị
cũng liệt kê assemblies khác mà nó phụ thuộc.
Nó là dạng giới hạn phiên bản. Assembly là đơn vị versionable nhỏ nhất trong
CLR; tất cả các loại và các tài nguyên trong cùng một assembly được dịch như
một đơn vị. Assembly mô tả sự phụ thuộc phiên bản bạn chỉ định cho bất kỳ hội
đồng phụ thuộc. Để biết thêm thông tin về phiên bản, thấy hội Versioning .
Nó là dạng một đơn vị triển khai. Khi một ứng dụng bắt đầu, chỉ assemblies là
ứng dụng ban đầu gọi phải sẵn sàng. Assemblies khác, chẳng hạn như ví trí các
tài nguyên hoặc assemblie có chứa lớp tiện ích, có thể được khôi phục và yêu
cầu. Điều này cho phép các ứng dụng được giữ đơn giản và nhỏ khi tải xuống
đầu tiên.
Nó là đơn vị mà sự thực thi side-by-side được hỗ trợ.
Đinh Ngọc Điệp CNTT-K36
Assemblies có thể là tĩnh hoặc động. Assemblies tĩnh có thể bao gồm .NET
Framework các loại (lớp và giao tiếp), cũng như các tài nguyên cho assembly
(bitmap, các file JPEG, file tài nguyên, vv). Assemblies tĩnh được lưu trữ trên đĩa
trong tập tin thực thi di động (PE). Bạn cũng có thể sử dụng .NET Framework để
tạo ra Assemblies động, được chạy trực tiếp từ bộ nhớ và sẽ không được lưu vào
đĩa trước khi thực thi. Bạn có thể lưu Assemblies động vào đĩa sau khi họ đã thực
thi.
Tập tin PE
Assembly được lưu trữ trên dĩa từ theo dạng thức tập tin Portable Executable
(PE). Dạng thức tập tin PE của .NET cũng giống như tập tin PE bình thường của
Windows NT. Dạng thức PE được cài đặt thành dạng thức tập tin DLL và EXE.
Về mặt logic, assembly chứa đựng một hay nhiều module. Mỗi module được tổ
chức thành một DLL và đồng thời mỗi module là một cấu thành của assembly. Các
module tự bản thân chúng không thể chạy được, các module phải kết hợp với nhau
thành assembly thì mới có thể làm được việc gì đó hữu ích.
Metadata
Metadata là thông tin được lưu trữ bên trong assembly với mục đích là để mô tả
các kiểu dữ liệu, các phương thức và các thông tin khác về assembly. Do có chứa
metadata nên assembly có khả năng tựmôtả.
Assembly tạo ra một giới hạn bảo vệ (security boundary). Các kiểu dữ liệu định
nghĩa bên trong assembly bị giới hạn phạm vi tại ranh giới assembly. Để có thể sử
dụng chung một kiểu dữ liệu giữa 2 assembly, cần phải chỉ định rõ bằng tham
chiếu (reference) trong IDE hoặc dòng lệnh.
Manifest
Manifest chính là một thành phần của metadata. Manifest mô tả một assembly
chứa những gì, ví dụ như: thông tin nhận dạng (tên, phiên bản), danh sách các kiểu
dữ liệu, danh sách các resource, danh sách các assembly khác được assembly này
tham chiếu đến ...
Đinh Ngọc Điệp CNTT-K36
Một assembly có thể chứa nhiều module, do đó manifest trong assembly còn có
thể chứa mã băm (hash code) của mỗi module lắp ghép thành assembly để bảo đảm
rằng khi thực thi, chỉ có thể nạp các module đúng phiên bản.
Chỉ cần một sự thay đổi rất rất nhỏ trong module là mã băm sẽ thay đổi.
Mỗi module cũng chứa riêng phần manifest mô tả cho chính nó giống như
assembly chứa manifest mô tả cho assembly vậy.
Manifest của assembly cũng có thể chứa tham chiếu đến các assembly khác.
Mỗi tham chiếu chứa đựng tên, phiên bản, văn hóa (culture), nguồn gốc
(originator),…
Thông tin về nguồn gốc chính là chữ ký số (digital signature) của lập trình viên
hay của công ty nơi cung cấp assembly mà assembly hiện tại đang tham chiếu đến.
Văn hóa là một đối tượng chứa thông tin về ngôn ngữ, cách trình bày của mỗi
quốc gia. Ví dụ như cách thể hiện ngày tháng: D/M/Y hay M-D-Y
Đa Module Assembly
Một assembly đơn module là một assembly chỉ gồm một module, module này
có thể là một tập tin EXE hoặc DLL. Manifest cho assembly đơn module được
nhúng vào trong module.
Một assembly đa module là một assembly bao gồm nhiều tập tin (ít nhất một
tập tin EXE hoặc DLL). Manifest cho assembly đa module có thể được lưu trữ
thành một tập tin riêng biệt hoặc được nhúng vào một module nào đó bất kỳ.
Nếu một dự án có nhiều lập trình viên mà dự án đó chỉ xây dựng bằng một
assembly, việc kiểm lỗi, biên dịch dự án,… là một “ác mộng” vì tất cả các lập trình
Đinh Ngọc Điệp CNTT-K36
viên phải hợp tác với nhau, phải kiểm tra phiên bản, phải đồng bộ hóa mã
nguồn,…
Nếu một ứng dụng lớn được xây dựng bằng nhiều assembly, khi cần cập nhật
(update) để sửa lỗi chẳng hạn, thì chỉ cần cập nhật một / vài assembly mà thôi.
Nếu một ứng dụng lớn được tổ chức từ nhiều assembly, chỉ có những phần mã
chương trình thường sử dụng / quan trọng thuộc một vài assembly là được nạp vào
bộ nhớ, do đó làm giảm bớt chi phí bộ nhớ, tăng hiệu suất hệ thống.
Các assembly nội bộ được ghi trên dĩa từ thành một tập tin EXE hoặc DLL
trong cùng thư mục với assembly chính hoặc trong các thư mục con của thư mục
chứa assembly chính. Để thực thi trên máy khác chỉ cần sao chép đúng cấu trúc thư
mục là đủ, không cần phải đăng ký với Registry.
Ví dụ:
Tạo project với class sau ,sau đó add refrences là ClassA.dll (file ClassA.dll
sinh ra từ project trước nằm trong thư mục bin\debug).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace sudungAssembly
{
class Program
{
static void Main(string[] args)
{
ClassA.Class1 a = new ClassA.Class1();
a.hienThi("Dinh Ngoc Diep");
Console.ReadLine();
}
}
}
Kết quả minh họa:
Khi viết ra một assembly đại loại như một control chẳng hạn, nếu tác giả của
control đó có ý định chia sẻ cho các lập trình viên khác thì anh / chị ta phải xây
dựng assembly đó đáp ứng các yêu cầu sau:
Để có thể chia sẻ assembly, assembly đó phải được đặt vào nơi gọi là Global
AssemblyCache(GAC). Đây là nơi được quy định bởi Common Language
Runtime (CLR) dùng để chứa assembly chia sẻ.
Ví dụ minh họa:
//chú ý :nếu không copy key.snk vào chung thư mục thì phải chỉ
//rõ đường dẫn
namespace ClassA
{
public class Class1
{
public void hienThi(String name)
{
Console.WriteLine("Xin chao ban " + name);
}
}
}
Giờ ta sẽ copy file ClassA.dll (nằm trong thư mục bin\debug của project
ClassA) đến thư mục C:\ (mục đích để dễ gõ lệnh)
class Program
{
static void Main(string[] args)
{
Class1 a = new Class1();
a.hienThi("Dinh Ngoc Diep");
Console.ReadLine();
}
}
}
Kết quả :
Giả sử bạn cài đặt một ứng dụng A lên một máy và nó chạy tốt. Sau đó bạn cài
đặt ứng dụng B, bỗng nhiên ứng dụng A không chịu hoạt động. Sau quá trình tìm
hiểu, cuối cùng nguyên nhân là do ứng dụng B đã cài một phiên bản khác đè lên
một tập tin DLL mà ứng dụng A sử dụng. Tình huống trên gọi là “xung đột DLL”
Tên mạnh
Đinh Ngọc Điệp CNTT-K36
Một tên mạnh là một chuỗi các ký tự hexa mang thuộc tính là duy nhất trong
toàn cầu (globally unique). Ngoài ra chuỗi đó còn được mã hóa bằng thuật toán
khóa công khai
Mã hóa khóa công khai – bí mật: đó là một thuật toán mã hóa đặc biệt, đầu tiên
dùng một thuật toán riêng tạo ra 2 khóa, một khóa phổ biến rộng rãi nên gọi là
khóa công khai, khóa còn lại do chủ nhân của nó cất nơi an toàn nên gọi là bí mật.
Sau đó dùng thuật toán mã hóa để mã hóa dữ liệu. Một khi dữ liệu bị mã hóa bằng
một khóa thì dữ liệu đó chỉ có thể được giải mã bằng khóa kia và ngược lại.Để bảo
đảm rằng assembly không bị thay đổi vô tình hay cố ý.
Để tạo ra tên mạnh, một cặp khóa công khai-bí mật được tạo ra cho assembly.
Một mã băm (hash code) được tạo ra từ tên, nội dung của các tập tin bên trong
assembly và chuỗi biểu diễn khóa công khai. Sau đó mã băm này được mã hóa
bằng khóa bí mật, kết quả mã hóa được ghi vào manifest. Quá trình trên được gọi
là ký xác nhận vào assembly (signing the assembly).
Khi assembly được CLR nạp vào bộ nhớ, CLR sẽ dùng khóa công khai trong
manifest giải mã mã băm để xác định xem assembly có bị thay đổi không.
Sau khi đã tạo tên mạnh và ghi vào assembly, việc còn lại để thực hiện chia sẻ
assembly là đặt assembly đó vào thư mục GAC. Đó là một thư mục đặc biệt dùng
để chứa assembly chia sẻ. Trên Windows, đó là thư mục \WinNT\assembly hoặc
C:\Windows\Assembly.
Ví dụ minh họa:
Mỗi assembly có số hiệu phiên bản riêng. Một “phiên bản” ám chỉ toàn bộ nội
dung của một assembly bao gồm cả kiểu dữ liệu và resource.
Assembly chia sẻ trong .NET được định vị bằng tên duy nhất (unique) và phiên
bản. Phiên bản được biểu diễn bởi 4 số phân cách bằng dấu ‘:’ ví dụ như
1:2:6:1246
Đinh Ngọc Điệp CNTT-K36
Số cuối cùng mô tả lần xem xét cập nhật (revision) để sửa lỗi
III. REFLECTION
Reflection được hiểu là một chức năng trong .Net cho phép đọc thông tin từ
các siêu dữ liệu (metadata) của assembly để tạo ra một đối tượng (có kiểu là
Type) bao gói các thông tin đó lại. Với reflection, bạn có thể trích xuất để
gọi và tạo ra các phương thức, truy cập và thay đổi các thuộc tính của đối
tượng một cách linh động trong quá trình runtime.
Ta có thể dùng phương thức GetType() của lớp Object để trả về đối
tượng kiểu Type mô tả kiểu dữ liệu của đối tượng. Có được đối tượng Type
này rồi, ta sẽ lấy thông tin của kiểu dữ liệu qua các thuộc tính của lớp Type.
Sau đây là một ví dụ đơn giản minh họa cách in ra tên kiểu dữ liệu của các
biến qua thuộc tính FullName của lớp Type:
Phương thức GetType() chỉ có thể lấy được thông tin từ các biến đối
tượng. Trong trường hợp muốn lấy thông tin của lớp thông qua tên lớp, bạn
phải sử dụng phương thức tĩnh Type.GetType(), tuy nhiên tham số truyền
vào cần phải ghi đầy đủ cả namespace.
Đinh Ngọc Điệp CNTT-K36
Console.WriteLine(mType1.FullName);
Console.WriteLine(mType2.FullName);
Console.Read();
}
Sử dụng toán tử typeof, bạn có thể lấy về đối tượng kiểu System.Type của
bất kì kiểu nào với cú pháp typeof(type).
static void Main()
{
Console.WriteLine(typeof(Int32).FullName);
Console.WriteLine(typeof(String).FullName);
Console.Read();
}
Cả ba ví dụ trên đều cho ra cùng kết quả khi được thực thi:
Lớp Type cung cấp đầy đủ các phương thức cho phép lấy các thông tin của
kiểu dữ liệu. Các phương thức này có dạng GetXXX(), mỗi phương thức trả
Đinh Ngọc Điệp CNTT-K36
về một hay một mảng đối tượng lưu trữ thông tin của mỗi thành viên trong
kiểu dữ liệu (bạn có thể nhận biết điều này thông qua cách đặt tên của các
phương thức ở dạng số nhiều hay số ít). Các kiểu trả về của các phương thức
này đều có hậu tố là Info: ConstructorInfo, EventInfo, FieldInfo,
InterfaceInfo, MemberInfo, MethodInfo, PropertyInfo.
Ví dụ để lấy tất cả thành viên public của một lớp ta dùng phương thức
GetMembers() như minh họa dưới đây:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace MinhHoa
{
class Program
{
class Nguoi
{ // Chỉ có mục đích minh họa
public string ten;
public static int tuoi;
public void hienThi() { }
}
static void Main()
{
Type mType = typeof(Nguoi);
MemberInfo[] m = mType.GetMembers();
Array.ForEach(m, mem =>
Console.WriteLine(mem.MemberType.ToString().PadRight(12) +
":" + mem));
Console.Read();
}
}
}
Khi chạy đoạn mã này bạn sẽ nhận được kết quả như sau:
Đinh Ngọc Điệp CNTT-K36
Ta sẽ trở lại với phần mở đầu của bài viết mà tôi nói về trường hợp thực thi
một phương thức dựa vào tên mà người dùng truyền vào. Hãy xem các
phương thức mà lớp Type cung cấp, có một phương thức tên là
GetMethod(string methodName). Giá trị trả về của phương thức này là một
đối tượng kiểu System.Reflection.MethodInfo chứa các thông tin về phương
thức. Và đây là một ví dụ đơn giản minh họa cách dùng phương thức này:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace MinhHoa
{
class Program
{
class MyClass
{
public void SayHello()
{
Console.WriteLine("Xin chao ban");
}
}
Đinh Ngọc Điệp CNTT-K36
myMethodInfo.Invoke(myClass, null);
Console.Read();
}
}
}
Bởi vì phương thức SayHello() trên không yêu cầu tham số nên ta sẽ
truyền null vào phương thức Invoke() của đối tượng MethodInfo. Đối với
các phương thức yêu cầu tham số, ta phải tạo một mảng object[] để truyền
giá trị vào. Hãy xem ví dụ sau:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
Đinh Ngọc Điệp CNTT-K36
namespace MinhHoa
{
class Program
{
class MyClass
{
public void SayHello(String name)
{
Console.WriteLine("Xin chao ban "+name);
}
}
}
}
Trong trường hợp có nhiều overload của phương thức SayHello(), nếu
bạn sử dụng phương thức GetMethod() trên thì sẽ nhận một exception với
thông báo “Ambiguous match found” trong lúc runtime. Nguyên nhân là do
chương trình không thể biết được phải lấy phương thức SayHello() nào. Lúc
đó bạn phải dùng một overload khác của GetMethod() để xác định các tham
số sẽ truyền vào phương thức SayHello(), và đây là ví dụ:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace MinhHoa
{
class Program
{
class MyClass
{
public void SayHello()
{
Console.WriteLine("Xin chao ban");
}
public void SayHello(string name)
{
Console.WriteLine("Xin chao ban "+ name);
}
}
static void Main()
{
Đinh Ngọc Điệp CNTT-K36
Thay vì dùng phương thức GetMethod(), bạn có thể dùng trực tiếp
phương thức instance của lớp Type là InvokeMember() với tham số thứ hai
là BindingFlags. InvokeMethod.:
public object InvokeMember(
string name,
BindingFlags invokeAttr,
Binder binder,
object target,
object[] args
);
Đinh Ngọc Điệp CNTT-K36
o Sử dụng
Khám phá các thành viên của lớp Type, bạn có thể đoán ra là có thể sử
dụng lớp ConstructorInfo để làm điều này.
Đinh Ngọc Điệp CNTT-K36
Phương thức GetConstructor(Type[] types) của lớp Type yêu cầu một
mảng kiểu Type theo đúng kiểu, trình tự và số lượng tham số mà constructor
cần lấy về yêu cầu. Trong trường hợp không có tham số, lớp Type cung cấp
sẵn một mảng Type rỗng là Type.EmptyTypes. Hãy xem hai ví dụ sau:
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace MinhHoa
{
class Program
{
class MyClass
{
string name;
public MyClass(string name)
{
this.name = name;
}
Một chút thay đổi và bạn có thể dễ dàng hiểu được. Tuy nhiên có thể
bạn thắc mắc về chuỗi tham số mà tôi sử dụng trong phương thức
Type.GetType(). Nếu để ý bạn có thể thấy MyClass là một lớp nằm bên
trong lớp Program (inner class), và để truy xuất đến lớp con ta phải dùng dấu
‘+’ để ko bị nhầm lẫn coi lớp Program là tên một namespace.
5. Lớp System.Activator
Bạn cảm thấy cách tạo instance như trên khá rắc rối, khó nhớ, và thực tế là
có một cách khác để làm điều này, mặc dù về căn bản nó vẫn là một. Như đã
nói trong phần trước, bởi vì yêu cầu tạo một instance từ tên kiểu khá phổ
biến, .Net cung cấp sẵn cho ta lớp System.Activator để làm được điều này.
Một giải pháp “nhỏ gọn” và giúp lập trình viên không phải dính tới những lí
thuyết rườm rà mà ít khi được ứng dụng trong công việc.
class MyClass1
{
public void SayHello()
{
Console.WriteLine("Xin chao ban ");
}
}
class MyClass2
{
string name;
public MyClass2(string name){this.name = name;}
public void SayHello()
{
Console.WriteLine("Xin chao ban " + name);
}
}
static void Main(string[] args)
{
Type mType1 =
Type.GetType("MinhHoa.Program+MyClass1");
Type mType2 =
Type.GetType("MinhHoa.Program+MyClass2");
object obj1 = Activator.CreateInstance(mType1);
object obj2 = Activator.CreateInstance(mType2,
"Dinh Ngoc Diep");
mType1.InvokeMember("SayHello",
BindingFlags.InvokeMethod, null, obj1, null);
mType2.InvokeMember("SayHello",
BindingFlags.InvokeMethod, null, obj2, null);
Console.Read();
}
}
}
Kết quả minh họa:
Đinh Ngọc Điệp CNTT-K36
6. Lớp System.Reflection.Assembly
Trong bài viết này tôi cũng có vài lần nhắc đến từ assembly, đây là
một khái niệm cơ bản trong .Net. Cũng xin nhắc lại một chút về khái niệm
này nếu như bạn đã bỏ lỡ nó khi bắt đầu tìm hiểu về .Net.
– Định nghĩa:.Net Assembly có thể được hiểu là kết quả của quá trình biên
dịch từ mã nguồn sang tập tin nhị phân dựa trên .Net framework. Là thành
phần cơ bản nhất .Net framework, assemly là thành phần không thể thiếu
trong bất kì ứng dụng .Net nào và được thể hiện dưới hai dạng tập tin là
EXE (process assembly) và DLL (library assembly). Assembly có thể được
lưu trữ dưới dạng single-file hoặc multi-file, tùy theo kiểu dự án mà bạn làm
việc.
Lớp Assembly cung cấp các phương thức tĩnh để nạp một assembly
thông qua AssemblyName, đường dẫn tập tin hoặc từ tiến trình đang chạy.
Bạn cũng có thể lấy Assembly dễ dàng từ property của lớp Type, ví dụ
typeof(int).Assembly.
Từ Assemly lấy được, bạn có thể dùng phương thức GetTypes() lấy
về các kiểu dữ liệu và thực hiện các kĩ thuật giống như trong phần về lớp
System.Type tôi đã nói tới.
}
}
}
Kết quả xuất ra:
Đáng chú ý nhất trong các thuộc tính này là thuộc tính Count. Đây là thuộc tính trả
về số lượng các phần tử có trong ArrayList.
Trong
các
phương thức này, đáng chú ý nhất có thể kể đến:
+ Add – thêm mới một đối tượng vào ArrayList
+ Remove – loại bỏ đối tượng khỏi ArrayList
+ Insert – Chèn một đối tượng mới vào ArrayList tại vị trí index cụ thể.
+ Sort – Sắp xếp ArrayList
Ví dụ với ArrayList:
Đinh Ngọc Điệp CNTT-K36
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace MinhHoa
{
class Program
{
static void Main(string[] args)
{
//Khởi tạo đối tượng
ArrayList al = new ArrayList();
//Thêm dữ liệu
al.Add(1);
al.Add(2);
al.Add(3);
//Sửa giá trị tại vị trí thứ 2 thành 10. Vị trí
thứ 2 có index = 1, do index bắt đầu từ 0
al[1] = 10;
//Xóa phần tử có giá trị bằng 3
al.Remove(3);
//Duyệt bằng chỉ mục index
for (int index = 0; index < al.Count; index++)
{
Console.WriteLine(al[index].ToString());
}
Console.WriteLine();
//Duyệt với foreach
foreach (int i in al)
{
Console.WriteLine(i);
}
Console.ReadLine();
}
}
}
2. Hashtable
Lớp Hashtable cho phép lưu trữ giá trị theo các cặp Key-Value. Thông qua các
khóa (Key), người dùng có thể dễ dàng thao tác đến các giá trị (Value) bên trong
Hashtable.
Chú ý: Do Hashtable sử dụng khóa để thao tác, nên các giá trị key này phải là duy
nhất.
Dưới đây là các phương thức và thuộc tính thông dụng của lớp Hashtable:
- Trong đó:
+ Count: Trả về số lượng các cặp key-value có trong Hashtable.
+ Keys: Trả về danh sách các Key trong Hashtable
+ Values: Trả về danh sách các Value trong Hashtable
- Trong đó:
+ Add: Phương thức cho phép thêm mới một cặp key và value vào
Hashtable. Để đảm bảo khóa Key không bị trùng, nên kiểm tra trước với
phương thức ContainsKey.
+ Remove: Xóa cặp key và value có trong Hashtable thông qua tham số key.
+ ContainsKey: Kiểm tra xem khóa key đã có trong Hashtable hay chưa.
Ví dụ với Hashtable:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace MinhHoa
{
class Program
Đinh Ngọc Điệp CNTT-K36
{
static void Main(string[] args)
{
//Khởi tạo đối tượng
Hashtable ha = new Hashtable();
//Thêm mới
ha.Add("hello", "Xin chao");
ha.Add("i", "toi");
ha.Add("they", "ho");
//Kiểm tra tồn tại
if (ha.ContainsKey("i"))
{
Console.WriteLine("Key=\"i\" đã có");
Console.WriteLine();
}
//Thay đổi giá trị của cặp có Key="they" thành
"no"
if (ha.ContainsKey(2))
{
ha["they"] = "no";
}
//Xóa key="they"
ha.Remove("they");
//Duyệt qua toàn bộ Key
foreach (String key in ha.Keys)
{
Console.WriteLine("Key: " + key);
Console.WriteLine("Value: " + ha[key]);
Console.WriteLine();
}
Console.WriteLine();
//Duyệt qua toàn bộ Value
foreach (String value in ha.Values)
{
Console.WriteLine("Value: " + value);
Console.WriteLine();
}
Console.ReadLine();
}
}
}
Đinh Ngọc Điệp CNTT-K36
Kết quả:
2.Lớp LinkedList
Phương thức
AddAfter(node, value) Thêm vào sau node giá trị value
AddAfter(node1, node2) Thêm node2 vào sau node1
AddFirst(value) Thêm value vào đầu danh sách
AddLast(value) Thêm value vào cuối danh sách
Clear() Xóa danh sách
RemoveFirst() Xóa phần tử đầu danh sách
RemoveLast() Xóa phần tử cuối danh sách
Remove(value) Xóa phần tử có giá trị là value
GetEnumerator() Lấy Enumerator của danh sách
Find(value) Trả về node có giá trị value đầu tiên
FindLast(value) Trả về node có giá trị value cuối
CopyTo(array[],index) Copy value của danh sách vào mảng array ,index là vị trí
của mảng array bắt đầu chép vào
Thuộc tính
Count Số phần tử của danh sách
First Phần tử đầu danh sách
Last Phần tử cuối danh sách
Đinh Ngọc Điệp CNTT-K36
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace MinhHoa
{
class Program
{
static void Main(string[] args)
{
LinkedList<String> list = new LinkedList<String>();
list.AddLast( "xin");
list.AddLast("chao");
list.AddLast("Ban");
list.AddLast("Dinh Ngoc Diep");
IEnumerator e = list.GetEnumerator();
while (e.MoveNext())
{
Console.WriteLine(e.Current.ToString());
}
Console.WriteLine("---------------------------------
--------");
String[] hoctap = { "Cong nghe .NET", "Thuc hanh lam
viec nhom", "Co so du lieu" };
foreach (String s in hoctap)
list.AddLast(s);
e = list.GetEnumerator();
while (e.MoveNext())
{
Console.WriteLine(e.Current.ToString());
}
Console.WriteLine("---------------------------------
--------");
list.RemoveFirst();
e = list.GetEnumerator();
while (e.MoveNext())
{
Console.WriteLine(e.Current.ToString());
}
Console.ReadLine();
}
}
}
Kết quả:
Đinh Ngọc Điệp CNTT-K36
2.Lớp SortList:
SortedList là lớp kết hợp của Hashtable và ArrayList, có nghĩa là các phần tử
trong tập hợp bao gồm key và value, các phần tử được truy xuất theo chỉ số. Sự
khác nhau giữa Hastable và SortedList là các phần tử trong SortedList được sắp
xếp theo key của nó. Việc thực thi chương trình sử dụng SortedList chậm hơn
chương trình sử dụng Hashtable do có quá trình sắp xếp các phần tử. Bảng dưới
đây liệt kê các phương thức và thuộc tính thông dụng của lớp SortedList.
Phương thức
Add Thêm phần tử
Remove Xóa phần tử
GetKey Trả về key của phần tử có chỉ số i
IndexOfKey Trả về chỉ số của một key
IndexOfValue Trả về chỉ số của value đầu tiên trong danh sách
ContainsKey Tìm kiếm key trong danh sách
getByIndex Trả về value ở vị trí index
Thuộc tính
Capacity Trả về số phần tử mà SortedList có thể chứa
Count Số phần tử trong SortedList
Đinh Ngọc Điệp CNTT-K36
Ví dụ minh họa:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace MinhHoa
{
class Program
{
static void Main(string[] args)
{
SortedList list = new SortedList();
list.Capacity = 10;//thiết lập list chứa được 100
phần tử
for(int i=1;i<10;i++)
list.Add(i, "so "+i);
Console.WriteLine("Key=>value");
for (int i = 0; i < list.Count; i++)
Console.WriteLine(list.GetKey(i).ToString() +
"=>" + list.GetByIndex(i).ToString());
Console.ReadLine();
}
}
}
Kết quả minh họa:
Đinh Ngọc Điệp CNTT-K36
3.Lớp Dictionary:
Là lớp tạo ra tập hợp các phần tử kiểu generic gồm có key và value, có nghĩa là
nó chỉ cho phép lưu một tập các phần tử có cặp key và value có cùng kiểu dữ liệu.
Dictonary không có cho phép lưu trữ giá trị null.
Cú pháp: Dictionary
Bảng dưới đây liệt kê các phương thức và thuộc tính thông dụng của lớp
Dictionary.
Phướng thức
Add Thêm phần tử
Remove Xóa phần tử
Clear Xóa tất cả key/value trong Dictionary
ContainsKey Tìm kiếm key trong Dictionary
ContainsValue Tìm kiếm value trong Dictionary
Thuộc tính
Count Số phần tử trong Dictionary
Keys Trả về tập key có trong Dictionary
Values Trả về tập value có trong Dictionary
Ví dụ minh họa:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace MinhHoa
{
class Program
{
static void Main(string[] args)
{
Dictionary<int,String> dic=new
Dictionary<int,string>();
for (int i = 1; i < 10; i++)
dic.Add(i, "So thu tu:" + i);
ICollection c = dic.Keys;
foreach (int k in c)
Console.WriteLine(k + "=>" + dic[k]);
Console.ReadLine();
Đinh Ngọc Điệp CNTT-K36
}
}
}