2010-12-11 4 views
8

Я только что попробовал свое первое использование дженериков в Delphi 2009 и недоумевал, как использовать общий тип в качестве входных данных для функции Supports, используемой для просмотра, реализует ли объект данный интерфейс. Я создал небольшой образец, иллюстрирующий проблему.Использование функции Supports() с общим типом интерфейса

Учитывая следующие виды и функции полезности:

IMyInterface = interface 
['{60F37191-5B95-45BC-8C14-76633826889E}'] 
end; 

TMyObject = class(TInterfacedObject, IMyInterface) 
end; 

class function TFunctions.GetInterface<T>(myObject: TObject): T; 
var 
    specificInterface: T; 
begin 
    // This would compile, but looses the generic capability 
    //Supports(myObject, IMyInterface, specificInterface); 

    // This results in compile errors 
    Supports(myObject, T, specificInterface); 

    result := specificInterface; 
end; 

и следующий фрагмент кода:

class procedure TFunctions.Test; 
var 
    myObject: TMyObject; 
    myInterface: IMyInterface; 
begin 
    myObject := TMyObject.Create; 

    myInterface := GetInterface<IMyInterface>(myObject); 
end; 

Я бы ожидать, никаких проблем, но я получаю следующие ошибки компиляции время:

[DCC Error] GenericExample.pas (37): E2029 '(' expected but ',' found [DCC Error] Gener icExample.pas (37): E2014 Заявление ожидалось, но выражение типа «Т» найдено

Я не уверен, что компилятор ожидает меня сделать с T при использовании в качестве фактического аргумента функции ,

Я искал вокруг совсем немного и не смог взломать этот. Часть меня подозревает, что если бы я мог понять, как имя интерфейса преобразуется в тип IID: TGUID во время компиляции, при использовании конкретного имени интерфейса я мог бы добиться некоторого прогресса, но это тоже уклонилось от меня.

Любая помощь очень ценится.

ответ

7

Нет гарантии, что T имеет связанный с ним GUID, и на этом языке нет средств для записи ограничения на параметр типа, чтобы сделать эту гарантию.

Имя интерфейса преобразуется в GUID компилятором, просматривающим имя в таблице символов, получая структуру данных компилятора, представляющую интерфейс, и проверяя соответствующее поле для GUID. Но generics не похожи на шаблоны C++; они должны быть скомпилированы и проверены типом и, как известно, работают для любого допустимого параметра типа, а это означает ограничение параметра типа в его объявлении.

Вы можете получить GUID с помощью RTTI (сначала проверьте, что T действительно представляет интерфейс) с чем-то вроде GetTypeData(TypeInfo(T))^.Guid и передайте GUID Supports таким образом.

+0

Не можете ли вы применить ограничение, что T должен быть определенным интерфейсом с GUID? –

+1

Если это должен быть какой-то интерфейс, тогда код не является общим. Поддержка вернет ссылку на интерфейс; компилятор не может в общем случае превратить это во все, что есть. –

+1

Барри, спасибо за помощь. Большая часть моего опыта работы с общим программированием была на фоне C++, и я ожидал, что компилятор узнает, имеет ли интерфейс Guid так же, как он знал бы, если бы имя интерфейса было предоставлено напрямую. Теперь имеет смысл знать, что генерические шаблоны <> C++. Еще раз спасибо. – Chad

3

Почему вы даже беспокоитесь?

Чтобы использовать эту TFunctions.GetInterface вам нужно:

  • интерфейс
  • ссылка на объект

Если у вас есть те, то вы можете просто позвонить Supports() напрямую:

intf := TFunctions.GetInterface<IMyInterface>(myObject); 

является точно equivale щ:

Supports(IMyInterface, myObject, intf); 

Использование дженериков здесь это пустая трата времени и усилий, и действительно возникает вопрос: «Почему это?».

Он просто делает вещи труднее читать (как это часто бывает с дженериков) и более громоздким для использования.

Опоры() возвращает удобное логическое значение, чтобы указать успех/провал, который вы должны проверить отдельно с помощью оболочки:

intf := TFunctions.GetInterface<IMyInterface>(myObject); 
    if Assigned(intf) then 
    // ... 

против:

if Supports(IMyInterface, myObject, intf) then 
    // We can use intf 

При создании обертки вокруг функциональности обычно бывает, что результатом является улучшение читабельности или удобства использования.

imho это не работает по обоим пунктам, и вы должны просто придерживаться Поддержка ().

+0

Мой пример перегоняется из фактического контекста, задавать конкретный вопрос и не является иллюстрацией фактического дизайна. – Chad

+2

Тогда вам нужно предоставить хотя бы НЕКОТОРЫЕ из контекста. В противном случае это похоже на вопрос о том, как добраться от A до B, не упоминая, что вы не можете ездить и не иметь денег на проезд в автобусе. Возможно, даже в том контексте, что вы делаете, это не лучший/самый простой способ этого. Все хорошо и хорошо, задавая конкретный вопрос, но если вы хотите получить полезные ответы, то не стоит выбрасывать важный контекст. – Deltics

+2

Я почтительно не согласен. Приветствия. – Chad

Смежные вопросы