"E2010 호환되지 않는 유형 : 'TGUID'및 'T'"오류는 어떻게 해결합니까?
이 기본 인터페이스 정의를 기반으로하는 수십 개의 인터페이스가있는 장치에서 작업하고 있기 때문에 이것은 약간 혼란 스럽습니다.
type
IDataObject = interface(IInterface)
['{B1B3A532-0E7D-4D4A-8BDC-FD652BFC96B9}']
function This: TDataObject;
end;
ISomeObject = interface(IDataObject)
['{7FFA91DE-EF15-4220-A43F-2C53CBF1077D}']
<Blah>
end;
이것은 그들 모두가 인터페이스 뒤에 클래스를 반환하는 'This'메서드를 가지고 있다는 것을 의미합니다. 때때로 listviews와 물건을 넣는 데 필요하지만이 질문에 대해서는 할 수있는 추가 함수가있는 일반 클래스를 원하기 때문에 실제로 중요하지 않습니다. 파생 된 인터페이스에 적용됩니다. (그리고 파생 된 인터페이스에는 고유 한 GUID가 있습니다.) 다음은 일반 클래스입니다.
type
Cast<T: IDataObject> = class(TDataObject)
class function Has(Data: IDataObject): Boolean;
class function Get(Data: IDataObject): T;
end;
너무 복잡해 보이지 않고 클래스 메서드를 사용하는 이유는 Delphi가 클래스에 있지 않는 한 전역 제네릭 함수를 지원하지 않기 때문입니다. 그래서 내 코드 Cast<ISomeObject>.Has(SomeObject)
에서 객체가 특정 인터페이스를 지원하는지 확인하는 데 사용하고 싶습니다 . 이 Get()
함수는 가능한 경우 개체를 특정 유형으로 반환하는 것입니다. 따라서 다음 구현 :
class function Cast<T>.Get(Data: IDataObject): T;
begin
if (Data.QueryInterface(T, Result) <> S_OK) then
Result := nil;
end;
class function Cast<T>.Has(Data: IDataObject): Boolean;
begin
Result := (Data.QueryInterface(T, Result) = S_OK);
end;
그리고 이것이 짜증나는 곳입니다! 내 코드의 다른 곳에서는 내가 사용 if (Source.QueryInterface(ISomeObject, SomeObject) = 0) then ...
하고 잘 작동합니다. 이러한 일반 메서드에서는 ISomeObject
로 대체되고 T
작동해야합니다. 그러나 컴파일을 거부하고 다음 오류를 제공합니다.
[dcc64 오류] DataInterfaces.pas (684) : E2010 호환되지 않는 유형 : 'TGUID'및 'T'
그리고 그것은 성가신 일입니다. 이 문제를 해결해야하지만 시스템 장치의 인터페이스 코드를 깊이 해킹하지 않고는 적절한 솔루션을 찾을 수 없습니다. (이 코드는 여러 다른 플랫폼에서 실행
되어야하므로이 코드에서 사용할 수있는 유일한 단위입니다!) QueryInterface가 TGUID를 매개 변수로 예상하기 때문에 오류는 정확하지만 ISomeObject에서 가져 오는 것 같습니다. 그럼 왜 T가 아니죠?
여기서 불가능한 일을하려는 것 같아요 ...
좀 더 구체적으로 말하면 Source.QueryInterface(ISomeObject, SomeObject)
다른 장치를 사용하지 않고도 잘 작동합니다. 따라서 해당 유형이 인터페이스로 제한되는 경우 제네릭 유형에서 작동 할 것으로 예상합니다. 그러나 그것은 사실이 아니며 ISomeObject를 받아들이는 동안 T를 받아들이지 않는 이유를 알고 싶습니다.
일반 인터페이스 유형이 아닌 일반 유형으로 실패하는 이유를 설명 할 수 있습니까?
답변
QueryInterface()
소요 TGUID
입력으로하지만, 인터페이스 타입은 아니다 TGUID
. 컴파일러는 선언 된 guid가있는 인터페이스 유형을 TGUID
변수에 할당 할 때 특별한 처리 기능을 가지고 있지만 인터페이스 제약 조건을 사용하는 Generic 매개 변수 내부에는 적용되지 않는 것 같습니다. 따라서 시도하는 작업을 수행하려면 런타임에 인터페이스의 RTTI를 읽어 실제를 추출 해야합니다TGUID
( RTTI를 사용하여 인터페이스에서 GUID 값을 가져올 수 있습니까? 참조 ). 예 :
uses
..., TypInfo;
class function Cast<T>.Get(Data: IDataObject): T;
var
IntfIID: TGUID;
begin
IntfIID := GetTypeData(TypeInfo(T))^.GUID;
if (Data.QueryInterface(IntfIID, Result) <> S_OK) then
Result := nil;
end;
class function Cast<T>.Has(Data: IDataObject): Boolean;
begin
Cast<T>.Get(Data) <> nil;
end;
즉, RTL이 이미 기본적으로 제공하는 기능을 복제하는 이유는 무엇입니까?
전체 Cast
클래스는 불필요합니다. SysUtils.Supports()대신 사용 하십시오 SysUtils
(유닛은 크로스 플랫폼입니다). 예 :
uses
..., SysUtils;
//if Cast<ISomeObject>.Has(SomeObject) then
if Supports(SomeObject, ISomeObject) then
begin
...
end;
...
var
Intf: ISomeObject;
//Intf := Cast<ISomeObject>.Get(SomeObject);
if Supports(SomeObject, ISomeObject, Intf) then
begin
...
end;
또한 인터페이스를 구현 객체 로 직접 캐스팅 IDataObject.This
할 수 있기 때문에 속성이 완전히 필요하지 않습니다 (Delphi는 D2010 이후 이러한 캐스팅을 지원했습니다). 예 :IDataObject
TDataObject
var
Intf: IDataObject;
Obj: TDataObject;
Intf := ...;
Obj := TDataObject(Intf);