Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  21:13[Войти] | [Зарегистрироваться]
Ответ на вопрос № 83618

14-12-2018 00:52
Добрый день!
Подскажите пожалуйста, как можно создать экземпляр объекта заданного типа, если тип передается обобщенным параметром?

type
  TCustomDataObject = class(TObject)
  ...
  end;

  TDataObject1 = class(TCustomDataObject)
  ...
  end;

  TDataObject2 = class(TCustomDataObject)
  ...
  end;

  TMyCreatorObject<T: TMyDataObject> = class(TObject)
    function CreateObject: T;
  end;

...

  function TMyCreatorObject<T>.CreateObject: T;
  begin
    Result := ................. // ??? Как создать объект типа Т, наследованного от TCustomDataObject ???
  end;


[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице.
Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.

17-12-2018 03:58
Поставил Delphi 10.3 Rio. Приведенные вами примеры кода теперь работают. Похоже разработчики продают сырой материал. Нельзя так лажать, когда выдаешь выпуск за релиз программы!
Упомянутую библиотеку AsyncCals удалось допилить в две строи кода. Остальные библиотеки нашел более новые версии, адаптированные под Rio. Даже казалось бы умершую RxLib.
Благодарю Вас за отзывчивость!

15-12-2018 23:26
В XE3 структура TTypeInfo выглядит так


  TTypeInfo = record
    Kind: TTypeKind;
    Name: TSymbolName;
    function NameFld: TTypeInfoFieldAccessor; inline;
  {TypeData: TTypeData}
    function TypeData: PTypeData; inline;
  end;


Я начинал с RTTI разбиратся с версии XE3. Так вот там для некоторых структур в частности для структуры TTypeData выполнялось то , что если в ней присутствует комментированное поле, то оно по факту и есть ;). Т.е. вы можете поробовать скорректировать код, считая что после Name идет поле TTypeData. Это если есть какието очень везкие причины не уходить с XE2. А так то лучше перейти на новую версию, конечно.

14-12-2018 11:55 | Комментарий к предыдущим ответам
В последней версии дженерики подправили, хотя может это и чуть раньше 10.3 было, но точно недавно. Хотя с одной стороны подправили, а с другой у меня моя библиотека которая в XE3 прекрасно компилировалась в 10.3 перестала, там причем какой то Internal Error. Там дженерик рекорд с переопоеделенными операциями и от него много типов пораждено.
Но кстати вариант с RTTI абсолютно точно будет работать в XE3. А вот первый не уверен сейчас, не могу проверить, могу проверить через пару дней только.

14-12-2018 11:03 | Сообщение от автора вопроса
Дело в том, что есть очень интересные разработки, развитие которых остановилось... К примеру приведенная здесь на сайте библиотека асинхронных вызовов AsyncCalls...

14-12-2018 10:32 | Комментарий к предыдущим ответам
Ну что тут скажешь. Пора версию менять тем более сейчас community edition бесплатно.

14-12-2018 10:23 | Комментарий к предыдущим ответам
"Сложный вариант" тоже не работает, поскольку в модуле System.TypInfo поле TypeData закомментировано.

  PPTypeInfo = ^PTypeInfo;
  PTypeInfo = ^TTypeInfo;
  TTypeInfo = record
    Kind: TTypeKind;
    Name: ShortString;
  {TypeData: TTypeData}
  end;


14-12-2018 10:03 | Комментарий к предыдущим ответам
Версия среды:
Embarcadero® Delphi® XE2 Version 16.0.4504.48759

Скопипастил один к одному "простое" решение. Та же ошибка:
"[DCC Error] Unit7.pas(34): E2568 Can't create new instance without CONSTRUCTOR constraint in type parameter declaration"

14-12-2018 08:11
Ok, вот еще вариант, чуть более хардкорный

uses RTTI, TypInfo;
{ TMyCreatorObject<T> }
class function TMyCreatorObject<T>.CreateObject(A:integer): T;
var
    ctx    : TRttiContext;
    rt    : TRttiType;
    Method : TRttiMethod;
    v      : TValue;
    Obj    : TObject;
begin
  ctx:=TRttiContext.Create;
  rt:=ctx.GetType(TypeInfo(T));//в общем случае надо проверять что T это класс, но в данном примере можно не делать
  Method:=rt.GetMethod('Create');
  V:=A;
  Obj:=Method.Invoke(rt.Handle^.TypeData^.ClassType,v).AsObject;
  Result:=Obj as T;
end;

в качестве второго параметра в методе Invoke надо передавать список аргументов. В данном примере у конструктора один параметр типа integer его и передаем.

14-12-2018 07:41
Поправка - проверил без конструкторов в классах потомках, только один виртуальный конструктор в базовом классе.

14-12-2018 07:40 | Вопрос к автору: запрос дополнительной информации
На самом деле в классах потомках я переопределял констркуторы вот так

{ TDataObject1 }

constructor TDataObject1.Create(A: integer);
begin
  inherited;
  FA:=FA+1;
end;

{ TDataObject2 }

constructor TDataObject2.Create(A: integer);
begin
  inherited;
  FA:=FA+2;
end;


Чтобы убедится что вызван конструктор того класса, который нужен. Для этого и приватное поле, а то в том примере что я привел сначала, оно бессмысленно :).Но сейчас проверил еще раз без конструкторов в базовых классах, все компилируется без ошибок.

14-12-2018 07:29 | Комментарий к предыдущим ответам
Такая ошибка возникает, если не определен виртуальный конструктор в базовом классе. Я этот код откомпилировал и проверил. версия 10.3, нет возможности в других проварить, но так вроде должно работать и в других версиях.

14-12-2018 06:24 | Комментарий к предыдущим ответам
W0lt, не получается, на строке

Result:=T.Create(A);


ошибка компилятора "E2568 Cant create new instance without CONSTRUCTOR constraint in type parametr declaration"

14-12-2018 06:06
Может я не чего то не понял, ну вроде же все просто, не пойму в чем проблема создать виртуальный конструктор в базовом классе. Переопределять его то не надо без необходимости. Я имел ввиду, что если вы в потомках захотите сделать конструктор у которого будут другие параметры (например добавятся дополнительные), то только тогда уже будет сложность и надо RTTI подключать. Для конкретики вот пример. Приватное поле просто для проверки, какой конструктор вызвался.

  TCustomDataObject = class(TObject)
  private
    FA:integer;
  public
    constructor Create(A:integer);virtual;
  end;

  TDataObject1 = class(TCustomDataObject)

  end;

  TDataObject2 = class(TCustomDataObject)

  end;

  TMyCreatorObject<T: TCustomDataObject> = class(TObject)
    class function CreateObject(A:integer): T;
  end;
implementation
{ TMyCreatorObject<T> }

class function TMyCreatorObject<T>.CreateObject(A:integer): T;
begin
  Result:=T.Create(A);
end;

{ TCustomDataObject }

constructor TCustomDataObject.Create(A: integer);
begin
  FA:=A;
end;

пример использования


var O1:TCustomDataObject;
    O2:TDataObject1;
    O3:TDataObject2;
begin
  O1:=TMyCreatorObject<TCustomDataObject>.CreateObject(1);
  O2:=TMyCreatorObject<TDataObject1>.CreateObject(2);
  O3:=TMyCreatorObject<TDataObject2>.CreateObject(3);

Будет вызван нужный конструктор. Смотрим приватное поле. Вроде ответ на ваш вопрос, по крайней мере на то как вы сформулировали его.

14-12-2018 05:46
Разве так не получится?
Result=T.Create;
или
Result=T.ClassType.Create;

14-12-2018 05:31 | Комментарий к предыдущим ответам
Делал уже так, хочется более изящное и универсальное решение :)

14-12-2018 03:53
Ну если вам в общем виде надо, то это совсем другая история. И в таком случае вот такое объявление  TMyCreatorObject<T: TMyDataObject>  просто лишнее. Поверте лучше в потомках сделать override конструкторы :). Иначе надо подключать RTTI , узнавать тип в рантайме и разбираться с методом Invoke струкутрой TValue и всеми другими прелестями :). Я чуть позже напишу пример.

14-12-2018 03:44 | Комментарий к предыдущим ответам
W0lt, тогда нет смысла делать обобщенный класс. Весь смысл, что бы не делать у потомков одинаковых переопределяемых конструкторов, а сосредоточиться на развитии их особенностей.

14-12-2018 03:40
В классе TCustomDataObject объявляете виртуальный конструктор. В потомке его переопределяете если надо (override) потом просто вызываете T.Create. Правда если надумаете в потомках менять параметры конструктора, то тогда надо определять какой имеенно класс у T в рантайме.

14-12-2018 02:46
Прошу прощения, в определении класса TMyCreatorObject<T> я не верно указал тип допустимых классов <T>. Правильно будет так:

type
  TCustomDataObject = class(TObject)
  ...
  end;

  TDataObject1 = class(TCustomDataObject)
  ...
  end;

  TDataObject2 = class(TCustomDataObject)
  ...
  end;

  TMyCreatorObject<T: TCustomDataObject> = class(TObject)
    function CreateObject: T;
  end;

...

  function TMyCreatorObject<T>.CreateObject: T;
  begin
    Result := ................. // ??? Как создать объект типа Т, наследованного от TCustomDataObject ???
  end;


Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
"Мы с тобой одной крови — ты и я!". Чьи это заветные слова?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования