Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (4.45 MB, 563 trang )
90
Chương 3: Miền ứng dụng, cơ chế phản chiếu, và siêu dữ liệu
Thu lấy đối tượng Type mô tả kiểu của đối tượng cần tạo, gọi phương thức
GetConstructor của nó để có được đối tượng System.Reflection.ConstructorInfo
mô tả phương thức khởi dựng cần dùng, sau đó thực thi phương thức
ConstructorInfo.Invoke.
Bước đầu tiên trong việc tạo một đối tượng bằng cơ chế phản chiếu là thu lấy đối tượng Type
mô tả kiểu của đối tượng cần tạo (xem mục 3.10 để biết thêm chi tiết). Khi có được đối tượng
Type, hãy gọi phương thức GetConstructor để thu lấy đối tượng ConstructorInfo mô tả một
trong các phương thức khởi dựng của kiểu này. Dạng thức thông dụng nhất của phương thức
GetConstructor là nhận một mảng Type làm đối số, và trả về đối tượng ConstructorInfo mô
tả phương thức khởi dựng nhận các đối số được chỉ định trong mảng Type. Để thu lấy đối
tượng ConstructorInfo mô tả phương thức khởi dựng mặc định (không có đối số), bạn hãy
truyền cho phương thức GetConstructor một mảng Type rỗng (sử dụng trường tĩnh
Type.EmptyTypes); đừng sử dụng null, nếu không GetConstructor sẽ ném ngoại lệ
System.ArgumentNullException. Nếu GetConstructor không tìm thấy phương thức khởi dựng
nào có chữ ký phù hợp với các đối số được chỉ định thì nó sẽ trả về null.
Môt khi đã có đối tượng ConstructorInfo như mong muốn, hãy gọi phương thức Invoke của
nó. Bạn phải cung cấp một mảng chứa các đối số mà bạn muốn truyền cho phương thức khởi
dựng. Phương thức Invoke sẽ tạo đối tượng mới và trả về một tham chiếu đến đối tượng đó
(bạn phải ép về kiểu phù hợp). Dưới đây là đoạn mã trình bày cách tạo một đối tượng
System.Text.StringBuilder, chỉ định nội dung ban đầu cho StringBuilder và sức chứa của
nó.
// Thu lấy đối tượng Type cho lớp StringBuilder.
Type type = typeof(System.Text.StringBuilder);
// Tạo Type[] chứa các đối tượng Type cho mỗi đối số
// của phương thức khởi dựng (một chuỗi và một số nguyên).
Type[] argTypes = new Type[] {typeof(System.String),
typeof(System.Int32)};
// Thu lấy đối tượng ConstructorInfo.
ConstructorInfo cInfo = type.GetConstructor(argTypes);
// Tạo object[] chứa các đối số cho phương thức khởi dựng.
object[] argVals = new object[] {"Some string", 30};
// Tạo đối tượng và ép nó về kiểu StringBuilder.
StringBuilder sb = (StringBuilder)cInfo.Invoke(argVals);
Chức năng phản chiếu thường được sử dụng để hiện thực các factory. Trong đó, bạn sử dụng
cơ chế phản chiếu để thể hiện hóa các lớp thừa kế một lớp cơ sở phổ biến hay hiện thực một
giao diện phổ biến. Thông thường, cả lớp cơ sở chung và giao diện chung đều được sử dụng.
Lớp cơ sở trừu tượng sẽ hiện thực giao diện và bất kỳ chức năng chung nào, sau đó mỗi hiện
thực cụ thể sẽ thừa kế lớp cơ sở.
Không có cơ chế nào để khai báo rằng mỗi lớp cụ thể phải hiện thực các phương thức khởi
dựng với các chữ ký cụ thể. Nếu muốn người khác (hãng thứ ba) hiện thực các lớp cụ thể thì
bạn phải chỉ rõ (trong tài liệu hướng dẫn) chữ ký của phương thức khởi dựng mà factory của
bạn gọi. Cách thông thường để tránh vấn đề này là sử dụng phương thức khởi dựng mặc định
(không có đối số), sau đó cấu hình đối tượng bằng phương thức và thuộc tính. Ví dụ dưới đây
sẽ hiện thực một factory dùng để tạo các đối tượng có hiện thực giao diện IPlugin.
91
Chương 3: Miền ứng dụng, cơ chế phản chiếu, và siêu dữ liệu
using System;
using System.Reflection;
// Giao diện chung mà tất cả các plug-in phải hiện thực.
public interface IPlugin {
string Description { get; set; }
void Start();
void Stop();
}
// Lớp cơ sở trừu tượng mà tất cả các plug-in phải dẫn xuất từ đây.
public abstract class AbstractPlugin : IPlugin {
// Chuỗi chứa lời mô tả plug-in.
private string description = "";
// Thuộc tính dùng để lấy lời mô tả plug-in.
public string Description {
get { return description; }
set { description = value; }
}
}
// Khai báo các thành viên của giao diện IPlugin.
public abstract void Start();
public abstract void Stop();
// Một hiện thực đơn giản cho giao diện IPlugin
// để minh họa lớp PluginFactory.
public class SimplePlugin : AbstractPlugin {
// Hiện thực phương thức Start.
public override void Start() {
Console.WriteLine(Description
}
+ ": Starting...");
// Hiện thực phương thức Stop.
public override void Stop() {
Console.WriteLine(Description + ": Stopping...");
}
}
// Factory dùng để tạo các đối tượng của IPlugin.
public sealed class PluginFactory {
public static IPlugin CreatePlugin(string assembly,
string pluginName, string description) {
// Thu lấy đối tượng Type cho plug-in được chỉ định.
Type type = Type.GetType(pluginName + ", " + assembly);
// Thu lấy đối tượng ConstructorInfo.
ConstructorInfo cInfo = type.GetConstructor(Type.EmptyTypes);
// Tạo đối tượng và ép nó về kiểu StringBuilder.
IPlugin plugin = (IPlugin)cInfo.Invoke(null);
// Cấu hình IPlugin mới.
plugin.Description = description;
}
return plugin;
}
Câu lệnh sau đây sẽ tạo đối tượng SimplePlugin bằng lớp PluginFactory:
92
Chương 3: Miền ứng dụng, cơ chế phản chiếu, và siêu dữ liệu
IPlugin plugin = PluginFactory.CreatePlugin(
"CreateObjectExample", // Tên assembly
"SimplePlugin",
// Tên lớp plug-in
"A Simple Plugin"
// Lời mô tả plug-in
);
Lớp System.Activator cung cấp hai phương thức tĩnh CreateInstance và
CreateInstanceFrom dùng để tạo các đối tượng dựa trên đối tượng Type hay chuỗi
chứa tên kiểu. Xem tài liệu .NET Framework SDK để biết thêm chi tiết.
13
Tạo một đặc tính tùy biến
Bạn cần tạo ra một đặc tính theo ý bạn.
Tạo một lớp dẫn xuất từ lớp cơ sở trừu tượng System.Attribute. Hiện thực các
phương thức khởi dựng, các trường, và các thuộc tính để cho phép người dùng
cấu hình đặc tính. Sử dụng System.AttributeUsageAttribute để định nghĩa:
• Những phần tử chương trình nào là đích của đặc tính
• Bạn có thể áp dụng nhiều thể hiện của đặc tính cho một phần tử chương
trình hay không
• Đặc tính có được thừa kế bởi các kiểu dẫn xuất hay không
Đặc tính cung cấp một cơ chế tổng quát cho việc kết hợp thông tin khai báo (siêu dữ liệu) với
các phần tử chương trình. Siêu dữ liệu này nằm trong assembly đã được biên dịch, cho phép
các chương trình thu lấy nó thông qua cơ chế phản chiếu lúc thực thi (xem mục 3.14.) Các
chương trình khác, đặc biệt là CLR, sử dụng thông tin này để xác định cách thức tương tác và
quản lý các phần tử chương trình.
Để tạo một đặc tính tùy biến thì hãy dẫn xuất một lớp từ lớp cơ sở trừu tượng
System.Attribute. Các lớp đặc tính tùy biến phải là public và có tên kết thúc bằng
“Attribute”. Một đặc tính tùy biến phải có ít nhất một phương thức khởi dựng công khai.
Các đối số của phương thức khởi dựng sẽ trở thành các đối số vị trí (positional parameter)
của đặc tính. Như với bất kỳ lớp nào khác, bạn có thể khai báo nhiều phương thức khởi dựng,
cho phép người dùng tùy chọn sử dụng các tập khác nhau của các đối số vị trí khi áp dụng đặc
tính. Bất kỳ thuộc tính và trường đọc/ghi công khai nào do đặc tính khai báo đều trở thành đối
số được nêu tên (named parameter).
Để điều khiển cách thức người dùng áp dụng đặc tính, hãy áp dụng đặc tính
AttributeUsageAttribute cho đặc tính tùy biến của bạn. Đặc tính AttributeUsageAttribute
hỗ trợ một đối số vị trí và hai đối số được nêu tên, được mô tả trong bảng 3.3. Các giá trị mặc
định chỉ định giá trị sẽ được áp dụng cho đặc tính tùy biến của bạn nếu bạn không áp dụng
AttributeUsageAttribute hoặc không chỉ định giá trị cho một thông số.
Bảng 3.3 Các thành viên thuộc kiểu liệt kê AttributeUsage
Thông số
Kiểu
Mô tả
Mặc định
93
Chương 3: Miền ứng dụng, cơ chế phản chiếu, và siêu dữ liệu
vị trí
Một thành viên thuộc kiểu liệt kê
System.AttributeTargets, chỉ định
phần tử chương trình mà đặc tính sẽ
có hiệu lực trên đó.
AttributeTargets.All
AllowMultiple
được nêu
tên
Đặc tính có thể được chỉ định nhiều
lần cho một phần tử hay không.
false
Inherited
được nêu
tên
Đặc tính có được thừa kế bởi các lớp
dẫn xuất hay các thành viên được
chép đè hay không.
true
ValidOn
Ví dụ dưới đây trình bày cách tạo một đặc tính tùy biến có tên là AuthorAttribute, cho phép
bạn xác định tên và công ty của người tạo ra lớp hay assembly. AuthorAttribute khai báo
một phương thức khởi dựng công khai, nhận một chuỗi chứa tên tác giả. Điều này yêu cầu
người sử dụng AuthorAttribute phải luôn cung cấp một đối số vị trí chứa tên tác giả. Company
là thuộc tính công khai (có thể dùng làm đối số được nêu tên), Name là thuộc tính chỉ-đọc
(không thể dùng làm đối số được nêu tên).
using System;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Assembly,
AllowMultiple = true, Inherited = false)]
public class AuthorAttribute : System.Attribute {
private string company; // Công ty của tác giả
private string name;
// Tên tác giả
// Khai báo phương thức khởi dựng công khai.
public AuthorAttribute(string name) {
this.name = name;
company = "";
}
// Khai báo thuộc tính Company có quyền set/get.
public string Company {
get { return company; }
set { company = value; }
}
}
// Khai báo thuộc tính Name chỉ-đọc.
public string Name{
get { return name;}
}
Dưới đây là cách sử dụng AuthorAttribute:
// Khai báo Square Nguyen là tác giả của assembly.
[assembly:Author("Square Nguyen", Company = "Goldsoft Ltd.")]
// Khai báo Square Nguyen là tác giả của lớp.
[Author("Square Nguyen", Company = "Goldsoft Ltd.")]
public class SomeClass {
§
}