2011-10-10 19 views
7

Tôi có Biểu mẫu Delphi cung cấp chức năng đằng sau đối tượng giao diện mà các phần khác của mã cũng nhận được tham chiếu thông qua thuộc tính thuộc Biểu mẫu. Tôi không thể ủy quyền chức năng giao diện cho một đối tượng con vì quá nhiều chức năng đó được phục vụ bởi các điều khiển/thành phần trên biểu mẫu. Tôi không thể sử dụng TAggregatedObject hoặc TContainedObject để liên kết tuổi thọ của các đối tượng giao tiếp được truyền xung quanh Form vì lớp TForm không kế thừa từ TinterfacedObject và Delphi không hỗ trợ đa kế thừa vì vậy tôi không thể trộn trong TInterfacedObject vào chuỗi kế thừa . Tình huống này có thể dẫn đến vi phạm truy cập nếu một Biểu mẫu bị hủy trong khi một số mã khác giữ một trong các tham chiếu giao diện được Biểu mẫu truyền đi. Bất cứ ai có thể nghĩ ra một giải pháp tốt cho vấn đề này?Cách an toàn trong Delphi cho một Biểu mẫu để phân phối các đối tượng giao diện gắn liền với tuổi thọ của nó?

Trả lời

9

Bạn có thể ủy quyền giao diện cho đối tượng con, chỉ cần có đối tượng đó chứa con trỏ nội bộ vào biểu mẫu để có thể truy cập vào điều khiển của biểu mẫu khi cần, không khác gì bạn đang làm ngay bây giờ.

Bạn có thể sử dụng TAggregateObject hoặc TContainedObject cho các nhu cầu của mình. Họ không yêu cầu Biểu mẫu xuất phát từ TInterfacedObject. Tất cả những gì họ yêu cầu là con trỏ giao diện IInterfaceTComponent có nguồn gốc từ IInterface (và ghi đè _AddRef()_Release() để tắt tính tham chiếu), vì vậy bạn có thể vượt qua Biểu mẫu (là con số TComponent) làm con trỏ yêu cầu IInterface.

Điều đó để lại vấn đề duy nhất còn lại - Biểu mẫu đóng trong khi tham chiếu giao diện hoạt động đang được giữ bởi mã khác. Giải pháp đơn giản nhất là hoặc 1) viết lại mã đó để không giữ các tham chiếu đó trong khi Biểu mẫu đang đóng hoặc 2) không cho phép Biểu mẫu đóng cho đến khi các tham chiếu đó được giải phóng.

+0

Lebeau, cảm ơn tôi sẽ sử dụng thông tin đó để sửa đổi mã của mình. –

+0

Xin lỗi câu hỏi cuối, nhưng bạn có thể chỉ cho tôi một tham chiếu tốt giải thích khi nào sử dụng TContainedObject thay vì TAggregatedObject? Tôi đã nhìn chằm chằm vào Trợ giúp Delphi trong một thời gian và không thể thực sự xác định các trường hợp sử dụng khác biệt. –

2

Lưu ý: Điều này sẽ chỉ hoạt động nếu người tiêu dùng của bạn cũng xuất phát từ TComponent.

Để tránh các tài liệu tham khảo chết bạn có thể truy vấn các IInterfaceComponentReference (có sẵn trên tất cả các TComponent) từ mẫu của bạn, hãy gọi GetComponent trên giao diện đó và gắn mình vào FreeNotification của trở Component/Form.

gì xảy ra bây giờ là: Khi Form bị phá hủy nó sẽ thông báo cho tất cả "listners" rằng đi của nó để tiêu diệt chính nó bằng cách gọi phương thức Notification trên người tiêu dùng với chính nó (theo mẫu) như AComponentopRemove như hoạt động. Vì vậy, cho phép bạn nil tham chiếu giao diện của bạn. Nhưng lưu ý rằng tham chiếu đối tượng và tham chiếu giao diện không được bằng nhau. Cũng đảm bảo gọi số RemoveFreeNotification khi bạn không cần thông báo nữa để tránh các cuộc gọi không cần thiết.

TSomeConsumer = class(TComponent) 
private 
    FInterfaceToAService: ISomeInterface;   
protected 
    procedure Notification(AComponent: TComponent; Operation: TOperation); override; 
public 
    procedure SetService(const Value: ISomeInterface); 
end; 

procedure TSomeConsumer.Notification(AComponent: TComponent; Operation: TOperation); 
begin 
    inherited; 
    if (Operation = opRemove) and (AComponent = TObject(FInterfaceToAService)) then 
    SetService(nil); // Takes care of niling the interface as well. 
end; 

procedure TSomeConsumer.SetService(const Value: ISomeInterface); 
var 
    comRef: IInterfaceComponentReference; 
begin 
    if Supports(FInterfaceToAService, IInterfaceComponentReference, comRef) then 
    comRef.GetComponent.RemoveFreeNotification(self); 

    FInterfaceToAService := Value; 

    if Supports(FInterfaceToAService, IInterfaceComponentReference, comRef) then 
    comRef.GetComponent.FreeNotification(self); 
end; 
+0

Rất tuyệt! Tôi không biết về điều đó. Bạn có thể mở rộng một chút về tuyên bố của bạn - "Nhưng lưu ý rằng tham chiếu đối tượng và tham chiếu giao diện không được bằng nhau."? –

+1

Vâng, một số lý do: a) bạn có thể thực hiện tùy chỉnh 'QueryInterface' có thể trả về một đối tượng giao tiếp mới trên mọi cuộc gọi. b) Thứ hai, bạn có thể ủy quyền Giao diện cho một thuộc tính (Win32), một lần nữa có thể tạo một đối tượng mới. c) Việc triển khai 'TObject.GetInterface' thêm một interfaceOffset vào địa chỉ.Giao diện mới được giới thiệu (Delphi 2010) cho đối tượng đúc về cơ bản được thực hiện bằng cách truy vấn một giao diện điểm đánh dấu trả về địa chỉ mục nhập của đối tượng. –

+0

Điều gì sẽ xảy ra nếu đối tượng và tham chiếu giao diện là bình đẳng và sai lầm phổ biến nhất của một lập trình viên kết thúc việc tạo ra tình huống không mong muốn đó là gì? –

Các vấn đề liên quan