2010-06-02 23 views
6

Tôi đang lưu trữ các giao diện nhỏ từ một loạt các đối tượng vào một cửa hàng 'TInterfaceList' duy nhất với mục đích cung cấp danh sách các loại giao diện cụ thể cho người dùng cuối. giao diện sẽ hiển thị hàm 'GetName' nhưng tất cả các phương thức khác là duy nhất cho loại giao diện đó. Ví dụ ở đây là hai giao diện:Cách lưu trữ và định vị nhiều loại giao diện trong một Delphi TInterfaceList

IBase = interface 
    //---------------------------------------- 
    function GetName : string; 
    //---------------------------------------- 
    end; 

    IMeasureTemperature = interface(IBase) 
    //------------------------------------ 
    function MeasureTemperature : double; 
    //---------------------------------------- 
    end; 

    IMeasureHumidity = interface(IBase) 
    //---------------------------------------- 
    function MeasureHumidity: double; 
    //---------------------------------------- 
    end; 

tôi đặt một số các giao diện vào một TInterfaceList đơn và sau đó tôi muốn quét danh sách cho một loại giao diện cụ thể (ví dụ như 'IMeasureTemperature') xây dựng một danh sách các con trỏ cho các đối tượng xuất các giao diện đó. Tôi muốn không đưa ra giả định về vị trí của các đối tượng đó, một số có thể xuất nhiều hơn một loại giao diện. Tôi biết tôi có thể làm điều này với một hệ thống phân cấp lớp bằng cách sử dụng một cái gì đó như:

If FList[I] is TMeasureTemperature then .. 

nhưng tôi muốn làm điều gì đó tương tự với loại giao diện, Có thể không?

+1

Bạn có thể muốn làm rõ liệu danh sách đầu tiên của bạn có chứa giao diện thực tế * loại * hoặc tham chiếu đến đối tượng * thể hiện * thực hiện các giao diện đó không. Dường như tất cả những người trả lời ở đây cho đến nay đã giả định sau này trong khi tôi đọc câu hỏi của bạn để nói về cái cũ ... sau đó một lần nữa bạn không thể lưu trữ giao diện * loại * trong một 'TInterfaceList' ... vì vậy tôi có thể sai ... –

Trả lời

2

Tôi đoán rằng có thể đáp ứng nhu cầu của bạn.

function InterfaceRefIsInterface(Intf : IUnknown; ExpectedIntf : TGUID) : Boolean; 
var vReference : IUnknown; 
begin 
    if Supports(Intf, ExpectedIntf, vReference) then 
    Result := Intf = vReference 
    else 
    Result := False; 
end; 

Tôi không chắc chắn bao hàm sẽ cư xử khi INTF và ExpectedIntf được thừa hưởng từ người khác, nhưng điều này sẽ trả về TRUE trong trường hợp INTF là một kết hợp chính xác của ExpectedIntf.

Trong ví dụ của bạn, IMeasureHumidity sẽ không trả lại đúng trên IMeasureTemperature, nhưng tôi không chắc nó sẽ phản ứng như thế nào với IBase. Theo thử nghiệm sơ bộ, nó cũng sẽ trả về FALSE trên IBase.

+0

Trừ khi 'ExpectedIntf' là' IUnknown', không có gì đảm bảo rằng 'Intf' sẽ bằng' vReference'. [Quy tắc triển khai QueryInterface] (http://msdn.microsoft.com/en-us/library/ms686590.aspx) hứa hẹn rằng một cuộc gọi đến QueryInterface sẽ thành công, nhưng chúng không yêu cầu bất kỳ con trỏ giao diện cụ thể nào được trả về. –

+0

Từ liên kết của riêng bạn "cuộc gọi tới QueryInterface với IID_IUnknown phải luôn trả về cùng giá trị con trỏ vật lý" và "Mọi giao diện phải có khả năng truy vấn bất kỳ giao diện nào khác trên đối tượng". Tôi không chắc chắn quy tắc nào bạn giới thiệu sẽ làm cho điều này thất bại. –

+0

Điều này làm việc tốt và làm chính xác những gì tôi đã hy vọng, mặc dù tôi cần phải nhìn rất khó khăn vào nó để xem những gì nó đang làm! Sẽ không bao giờ có trường hợp giao diện IBase kế thừa sẽ được chuyển. Cảm ơn nhiều. –

6

Chỉ cần sử dụng Hỗ trợ, như thế này:

var 
    oMTIntf: IMeasureTemperature; 
... 
    If Supports(FList[I], IMeasureTemperature, oMTIntf) then .. 
+0

@ da-soft: Đề xuất hay nhưng không thành công khi một lớp đơn xuất hai giao diện khác nhau - 'Hỗ trợ' trả về true trong trường hợp đó cho mỗi giao diện. Tôi cần một số cách để xác định loại giao diện thực tế. –

+0

Rất tiếc, có vẻ như tôi đã bỏ lỡ điểm chính của bạn. Bạn có cần phải nhận được đối tượng từ giao diện, hoặc để có được giao diện từ giao diện? Nếu trước tiên, sau đó http://www.malcolmgroves.com/blog/?p=500. Nếu thứ hai, sau đó như tôi đã viết (tôi đã chỉnh sửa tin nhắn của tôi). –

+0

@Brian: Tại sao lại là một vấn đề? Nếu một trong hai giao diện đi xuống từ một giao diện khác, sau đó kiểm tra lớp con cháu trước lớp cha. Và nếu không, thì cả hai kết quả đều có giá trị như nhau. –

2

Bạn có thể sử dụng Supports chức năng trong SysUtils, họ là khá an toàn (trừ khi bạn thử chúng trên bộ nhớ unitialized) và bạn chỉ cần một biến mục tiêu của chính xác loại giao diện bạn cố gắng truyền tới:


procedure DoSomethingInList(AList: IInterfaceList;); 
var 
    i: Integer; 
    liItem: IInterface; 
    liMeasureTemp: IMeasureTemperature; 
    liMeasureHumi: IMeasureHumidity; 
begin 
    AList.Lock; 
    try 
    for i := 0 to AList.Count - 1 do 
    begin 
     liItem := AList[i]; 
     if Supports(liItem, IMeasureTemperature, liMeasureTemp) then 
     //... liMeasureTemp.MeasureTemperature ... 
     else if Supports(liItem, IMeasureHumidity, liMeasureHumi) then 
     //... liMeasureHumi.MeasureHumidity ... 
     else 
     //... 
    end; 
    finally 
    AList.Unlock; 
    end; 
end; 
Các vấn đề liên quan