1. Trang chủ
  2. » Công Nghệ Thông Tin

Tài liệu Các giao diện và mẫu phần 3 pdf

9 357 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Giao diện IEnumerable và Lớp Team
Định dạng
Số trang 9
Dung lượng 178,96 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Ä Hiện thực lớp khả-hủy disposable class Í Bạn cần tạo một lớp có tham chiếu đến các tài nguyên không-được-quản-lý và cung cấp một cơ chế để người dùng giải phóng các tài nguyên đó mộ

Trang 1

// Lớp Team mô tả tập hợp các đối tượng TeamMember Hiện thực giao diện // IEnumerable để hỗ trợ việc liệt kê các đối tượng TeamMember

public class Team : IEnumerable {

// TeamMemberEnumerator là một lớp private lồng bên trong, cung cấp // chức năng liệt kê các đối tượng TeamMember trong tập hợp

// Team Vì là lớp lồng bên trong nên TeamMemberEnumerator

// có thể truy xuất các thành viên private của lớp Team

private class TeamMemberEnumerator : IEnumerator {

private Team sourceTeam;

// Giá trị luận lý cho biết Team nằm dưới có thay đổi hay không

private bool teamInvalid = false;

// Giá trị nguyên cho biết TeamMember hiện tại (chỉ số

// trong ArrayList) Giá trị ban đầu là -1

private int currentMember = -1;

// Phương thức khởi dựng (nhận một tham chiếu đến Team)

internal TeamMemberEnumerator(Team team) {

this.sourceTeam = team;

sourceTeam.TeamChange +=

new TeamChangedEventHandler(this.TeamChange);

}

// Hiện thực thuộc tính IEnumerator.Current

public object Current {

get {

// Nếu TeamMemberEnumerator đứng trước phần tử đầu tiên // hoặc sau phần tử cuối cùng thì ném ngoại lệ

if (currentMember == -1 ||

currentMember > (sourceTeam.teamMembers.Count-1)) { throw new InvalidOperationException();

}

Trang 2

// Nếu không, trả về TeamMember hiện tại

return sourceTeam.teamMembers[currentMember];

}

}

// Hiện thực phương thức IEnumerator.MoveNext

public bool MoveNext() {

// Nếu Team nằm dưới bất hợp lệ, ném ngoại lệ

if (teamInvalid) {

throw new InvalidOperationException("Team modified"); }

// Nếu không, tiến đến TeamMember kế tiếp

currentMember++;

// Trả về false nếu ta dịch qua khỏi TeamMember cuối cùng

if (currentMember > (sourceTeam.teamMembers.Count-1)) { return false;

} else {

return true;

}

}

// Hiện thực phương thức IEnumerator.Reset Phương thức này // reset vị trí của TeamMemberEnumerator về đầu tập hợp Team public void Reset() {

// Nếu Team nằm dưới bất hợp lệ, ném ngoại lệ

if (teamInvalid) {

throw new InvalidOperationException("Team modified"); }

// Dịch con trỏ currentMember về trước phần tử đầu tiên currentMember = -1;

}

Trang 3

// Phương thức thụ lý sự kiện tập hợp Team nằm dưới thay đổi

internal void TeamChange(Team t, EventArgs e) {

// Báo hiệu Team nằm dưới hiện đang bất hợp lệ

teamInvalid = true;

}

}

// Ủy nhiệm dùng để chỉ định chữ ký mà tất cả

// các phương thức thụ lý sự kiện phải hiện thực

public delegate void TeamChangedEventHandler(Team t, EventArgs e);

// ArrayList dùng để chứa các đối tượng TeamMember

private ArrayList teamMembers;

// Sự kiện dùng để báo cho TeamMemberEnumerator

// biết Team đã thay đổi

public event TeamChangedEventHandler TeamChange;

// Phương thức khởi dựng Team

public Team() {

teamMembers = new ArrayList();

}

// Hiện thực phương thức IEnumerable.GetEnumerator

public IEnumerator GetEnumerator() {

return new TeamMemberEnumerator(this);

}

// Thêm một đối tượng TeamMember vào Team

public void AddMember(TeamMember member) {

teamMembers.Add(member);

if (TeamChange != null) {

Trang 4

TeamChange(this, null);

}

}

}

Nếu lớp tập hợp của bạn chứa nhiều kiểu dữ liệu khác nhau và bạn muốn liệt kê chúng một cách riêng rẽ, việc hiện thực giao diện IEnumerable trên lớp tập hợp này thì vẫn còn thiếu Trong trường hợp này, bạn cần hiện thực một số thuộc tính trả về các thể hiện khác nhau của IEnumerator Ví dụ, nếu lớp Team mô tả cả các thành viên và các máy tính trong đội, bạn có thể hiện thực các thuộc tính này như sau:

// Thuộc tính dùng để liệt kê các thành viên trong đội

public IEnumerator Members {

get {

return new TeamMemberEnumerator(this);

}

}

// Thuộc tính dùng để liệt kê các computer trong đội

public IEnumerator Computers {

get {

return new TeamComputerEnumerator(this);

}

}

Khi đó, bạn có thể sử dụng các enumerator này như sau:

Team team = new Team();

§

foreach(TeamMember in team.Members) {

// Làm gì đó

}

foreach(TeamComputer in team.Computers) {

// Làm gì đó

}

Lệnh foreach cũng hỗ trợ các kiểu có hiện thực một mẫu tương đương với mẫu được định nghĩa bởi giao diện IEnumerable và IEnumerator, mặc dù kiểu đó không hiện thực các giao diện này Tuy nhiên, mã lệnh của bạn sẽ rõ ràng hơn

và dễ hiểu hơn nếu bạn hiện thực giao diện IEnumerable Bạn hãy xem C# Language Specification để biết chi tiết về các yêu cầu của lệnh foreach [http://msdn.microsoft com/net/ecma]

Trang 5

Ä Hiện

thực lớp khả-hủy (disposable class)

Í Bạn cần tạo một lớp có tham chiếu đến các tài nguyên không-được-quản-lý và cung cấp một cơ chế để người dùng giải phóng các tài nguyên đó một cách tất định

Hiện thực giao diện System.IDisposable, và giải phóng các tài nguyên không-được-quản-lý khi mã client gọi phương thức IDisposable.Dispose

Một đối tượng không được tham chiếu đến vẫn tồn tại trên vùng nhớ động (heap) và tiêu thụ các tài nguyên cho đến khi bộ thu gom rác (Garbage Collector) giải phóng đối tượng

và các tài nguyên Bộ thu gom rác sẽ tự động giải phóng các tài nguyên được-quản-lý (như bộ nhớ), nhưng nó sẽ không giải phóng các tài nguyên không-được-quản-lý (như file handle và kết nối cơ sở dữ liệu) được tham chiếu bởi các đối tượng được-quản-lý Nếu một đối tượng chứa các thành viên dữ liệu tham chiếu đến các tài nguyên không-được-quản-lý, đối tượng này phải giải phóng các tài nguyên đó

Một giải pháp là khai báo một destructor—hay finalizer—cho lớp Trước khi giải phóng phần bộ nhớ do một thể hiện của lớp sử dụng, bộ thu gom rác sẽ gọi finalizer của đối tượng này Finalizer có thể thực hiện các bước cần thiết để giải phóng các tài nguyên không-được-quản-lý Vì bộ thu gom rác chỉ sử dụng một tiểu trình để thực thi tất cả các finalizer, việc sử dụng finalizer có thể bất lợi trong quá trình thu gom rác và ảnh hưởng đến hiệu năng của ứng dụng Ngoài ra, bạn không thể kiểm soát khi bộ thực thi giải phóng các tài nguyên không-được-quản-lý vì bạn không thể trực tiếp gọi finalizer của một đối tượng, và bạn chỉ có quyền kiểm soát hạn chế trên các hoạt động của bộ thu gom rác bằng lớp System.GC

Bằng cách sử dụng finalizer, NET Framework định nghĩa mẫu Dispose như một phương

tiện cung cấp quyền kiểm soát khi bộ thực thi giải phóng các tài nguyên

không-được-quản-lý Để hiện thực mẫu Dispose, lớp phải hiện thực giao diện IDisposable Giao diện

này khai báo một phương thức có tên là Dispose; trong đó, bạn phải hiện thực phần mã cần thiết để giải phóng các tài nguyên không-được-quản-lý

Các thể hiện của các lớp có hiện thực mẫu Dispose được gọi là các đối tượng khả-hủy (disposable object) Khi mã lệnh đã hoàn tất với một đối tượng khả-hủy, nó sẽ gọi

phương thức Dispose của đối tượng để giải phóng các tài nguyên không-được-quản-lý, vẫn dựa vào bộ thu gom rác để giải phóng các tài nguyên được-quản-lý của đối tượng Cần hiểu rằng bộ thực thi không bắt buộc hủy các đối tượng; việc gọi phương thức

Dispose là nhiệm vụ của client Tuy nhiên, vì thư viện lớp NET Framework sử dụng mẫu Dispose rộng khắp nên C# cung cấp lệnh using để đơn giản hóa việc sử dụng các đối

tượng khả-hủy Đoạn mã sau trình bày cấu trúc của lệnh using:

using (FileStream fileStream = new FileStream("SomeFile.txt",

Trang 6

FileMode.Open)) {

// Làm gì đó với đối tượng fileStream

}

Dưới đây là một số điểm cần lưu ý khi hiện thực mẫu Dispose:

1 Mã client nên có khả năng gọi đi gọi lại phương thức Dispose mà không gây ra các ảnh hưởng bất lợi

2 Trong các ứng dụng hỗ-trợ-đa-tiểu-trình, điều quan trọng là chỉ có một tiểu trình thực thi phương thức Dispose Thông thường, bảo đảm sự đồng bộ tiểu trình là nhiệm vụ của mã client, mặc dù bạn có thể hiện thực sự đồng bộ bên trong phương thức Dispose

3 Phương thức Dispose không nên ném ngoại lệ

4 Vì phương thức Dispose dọn dẹp tất cả nên không cần gọi finalizer của đối tượng Phương thức Dispose của bạn nên gọi phương thức GC.SuppressFinalize để bảo đảm finalizer không được gọi trong quá trình thu gom rác

5 Hiện thực một finalizer sao cho phương thức Dispose sẽ được nó gọi theo một cơ chế an toàn trong trường hợp mã client gọi Dispose không đúng Tuy nhiên, nên tránh tham chiếu đến các đối tượng được-quản-lý trong finalizer vì không rõ trạng thái của đối tượng

6 Nếu một lớp khả-hủy thừa kế một lớp khả-hủy khác, phương thức Dispose của lớp con phải gọi phương thức Dispose của lớp cha Gói phần mã của lớp con trong một khối try và gọi phương thức Dispose của lớp cha trong một mệnh đề finally để bảo đảm việc thực thi

7 Các phương thức và thuộc tính khác của lớp nên ném ngoại lệ System.ObjectDisposedException nếu mã client thực thi một phương thức trên một đối tượng đã bị hủy

Lớp DisposeExample dưới đây minh họa một hiện thực phổ biến của mẫu Dispose:

using System;

// Hiện thực giao diện IDisposable

public class DisposeExample : IDisposable {

// Phần tử dữ liệu private dùng để báo hiệu

// đối tượng đã bị hủy hay chưa

bool isDisposed = false;

// Phần tử dữ liệu private dùng để lưu giữ

// handle của tài nguyên không-được-quản-lý

Trang 7

private IntPtr resourceHandle;

// Phương thức khởi dựng

public DisposeExample() {

// Thu lấy tham chiếu đến tài nguyên không-được-quản-lý

// resourceHandle =

}

// Destructor/Finalizer

~DisposeExample() {

// Gọi phiên bản nạp chồng protected của Dispose

// và truyền giá trị "false" để cho biết rằng

// Dispose đang được gọi trong quá trình thu gom rác,

// chứ không phải bởi mã consumer

Dispose(false);

}

// Hiện thực public của phương thức IDisposable.Dispose, được gọi // bởi consumer của đối tượng để giải phóng các tài nguyên không- // được-quản-lý một cách tất định

public void Dispose() {

// Gọi phiên bản nạp chồng protected của Dispose và truyền // giá trị "true" để cho biết rằng Dispose đang được gọi

// bởi mã consumer, chứ không phải bởi bộ thu gom rác

Dispose(true);

// Vì phương thức Dispose thực hiện tất cả việc dọn dẹp cần // thiết nên bảo đảm bộ thu gom rác không gọi destructor của lớp GC.SuppressFinalize(this);

}

// Phiên bản nạp chồng protected của phương thức Dispose Đối số // disposing cho biết phương thức được gọi bởi mã consumer (true), // hay bởi bộ thu gom rác (false)

protected virtual void Dispose(bool disposing) {

Trang 8

if (!isDisposed) {

if (disposing) {

// Phương thức này được gọi bởi mã consumer Gọi // phương thức Dispose của các thành viên dữ liệu // được-quản-lý có hiện thực giao diện IDisposable // §

}

// Giải phóng tất cả các tài nguyên không-được-quản-lý // và thiết lập giá trị của các thành viên dữ liệu

// được-quản-lý thành null

// Close(resourceHandle);

}

// Báo rằng đối tượng này đã bị hủy

isDisposed = true;

}

// Trước khi thực thi bất kỳ chức năng nào, bảo đảm rằng

// Dispose chưa được thực thi trên đối tượng

public void SomeMethod() {

// Ném một ngoại lệ nếu đối tượng đã bị hủy

if (isDisposed) {

throw new ObjectDisposedException("DisposeExample"); }

// Thực thi chức năng của phương thức

// §

}

public static void Main() {

// Lệnh using bảo đảm phương thức Dispose được gọi

// cả khi ngoại lệ xảy ra

using (DisposeExample d = new DisposeExample()) {

Trang 9

// Làm gì đó với d }

}

}

Ngày đăng: 21/01/2014, 01:20

🧩 Sản phẩm bạn có thể quan tâm