Приведение от TObject к типу интерфейса

связанный с моим последним вопросом, теперь у меня есть следующая проблема:

function TNodeFactory <T>.CreateNode (ID : Integer) : INodeInterface <T>;
var
  NodeClass : TClass;
begin
  NodeClass := FindRegisteredClass (ID);
  Result := NodeClass.Create;      
end;

Это дает ошибку компилятора:

E2010 Incompatible Types: 'INodeInterface<TNodeFactory<T>.T>' and 'TObject'

Приведение тоже не работает.

Что мне здесь не хватает?

EDIT: текущая реализация

TNodeFactory <T> = class
private
  type
    TRegisteredNodeType = record
      ID : Integer;
      NodeClass : TClass;
    end;
private
  FNodeTypeList : TList <TRegisteredNodeType>
public
  procedure RegisterNodeType (ID : Integer; NodeClass : TClass);
  function  CreateNode (ID : Integer) : INodeInterface <T>;
end;

procedure TNodeFactory <T>.RegisterNodeType (ID : Integer; NodeClass : TClass);
var
  RegisteredType : TRegisteredNodeType;
begin
  RegisteredType.ID := ID;
  RegisteredType.NodeClass := NodeClass;
  FNodeTypeList.Add (RegisteredType);
end;

function TNodeFactory <T>.CreateNode (ID : Integer);
var
  RegisteredType : TRegisteredNodeType;
begin
  for RegisteredType in FNodeTypeList do
    if (RegisteredType.ID = ID) then
      Exit (RegisteredType.NodeClass.Create);
  raise EInvalidNodeType.Create ('No node type with ID ' + IntToStr (ID) + ' registered');
end;

(упрощены и удалены проверки ошибок)


person jpfollenius    schedule 06.08.2009    source источник
comment
NodeClass — это TClass. Если вы создадите NodeClass, это будет просто TObject, а не INodeInterface. Вам нужно будет показать нам свою реализацию RegisterClass и FindRegisteredClass.   -  person Lieven Keersmaekers    schedule 06.08.2009
comment
добавил реализацию к моему вопросу   -  person jpfollenius    schedule 06.08.2009
comment
Вы можете попробовать Result := TInterfacedObject(RegisteredType.NodeClass).Create as INodeInterface   -  person Lieven Keersmaekers    schedule 06.08.2009
comment
или измените тип RegisterNodeType на ...(ID: Integer; NodeClass : TInterfacedObjectClass). и вернуть Result := RegisteredType.NodeClass.Create as INodeInterface. Вам нужно будет где-нибудь добавить объявление класса TInterfacedObjectClass = class of TInterfacedObject;.   -  person Lieven Keersmaekers    schedule 06.08.2009
comment
@Lieven: +1, кажется, это работает. Может быть, вы хотите поместить это как ответ, чтобы я мог принять его?   -  person jpfollenius    schedule 06.08.2009


Ответы (4)


Проблема в том, что NodeClass является TClass. Если вы создадите NodeClass, это будет просто TObject, а не INodeInterface.

Вы могли бы попробовать

Result := TInterfacedObject(RegisteredType.NodeClass).Create as INodeInterface

или измените RegisterNodeType на

type
  TInterfacedObjectClass = class of TInterfacedObject;   
...   
procedure RegisteredNodeType...(ID: Integer; NodeClass : TInterfacedObjectClass);

и вернуться

Result := RegisteredType.NodeClass.Create as INodeInterface. 
person Lieven Keersmaekers    schedule 06.08.2009

Вам нужно использовать функцию Supports() для извлечения ссылки на интерфейс из объекта. Вы найдете его в SysUtils.

Есть несколько перегруженных версий, вам нужна версия с тремя параметрами, с которой третий параметр «out» возвращает вам ссылку на ваш интерфейс.

person LachlanG    schedule 06.08.2009

В Delphi интерфейс не является объектом. И Interface-Pointer не является Objectpointer, поэтому вы не можете их использовать. Вам нужно использовать QueryInterface и запросить интерфейс.

function QueryInterface(var IID: TGUID; out Obj: Type):HRESULT

если HRESULT равен S_OK, то obj содержит ссылку на запрошенный интерфейс.

К сожалению, Delphi (Win32) обрабатывает интерфейсы, отличные от .NET/Java.

person Tobias Langner    schedule 06.08.2009
comment
@Smasher: если вы посмотрите на код Supports(), вы увидите, что он вызывает QueryInterface(), поэтому вы можете использовать любой из них. - person LachlanG; 06.08.2009
comment
+1 Не пробовал, так как у меня работает решение Ливена. Но спасибо! - person jpfollenius; 06.08.2009

Позвольте мне начать свой ответ с этого раскрывателя: я не очень хорошо знаком с использованием шаблонов в Delphi.

Вы получаете ошибку компилятора, потому что пытаетесь вернуть NodeClass, который определен как экземпляр TClass. Однако функция ожидает, что вы вернете экземпляр класса, реализующего INodeInterface. Возможно, вы сможете решить эту проблему с чем-то вроде этого

Result := INodeInterface(NodeClass.Create);     

or

function TNodeFactory <T>.CreateNode (ID : Integer) : INodeInterface <T>;
var
  NodeClass : TClass;
  NodeInterface: INodeInterface;
begin
  NodeClass := FindRegisteredClass (ID);
  NodeInterface:= NodeClass.Create;
  Result := NodeInterface;      
end;

Возможно, это неправильный ответ, но я надеюсь, что это поможет вам найти решение.

person Lawrence Barsanti    schedule 06.08.2009
comment
Как я уже говорил в вопросе: приведение тоже не работает. А вторая версия ИМХО просто более длинная версия первой. Спасибо, в любом случае! - person jpfollenius; 06.08.2009