powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Cоздать объект по типу, записанному в строке
30 сообщений из 30, показаны все 2 страниц
Cоздать объект по типу, записанному в строке
    #39712618
aXS_new
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Можно ли создать объект по типу, записанному в строке? Что-то вроде

Код: pascal
1.
obj := TClass.create();



только тип данных, к примеру, считан из файла. Понимаю, что можно перебирать через условие и создавать объекты по совпадению с определенным типом, но интересует, есть ли возможность сделать это без кучи условий.
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39712624
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aXS_newПонимаю, что можно перебирать через условие и создавать объекты по совпадению с
определенным типом, но интересует, есть ли возможность сделать это без кучи условий.

Нельзя. Но с RegisterClass ты можешь спрятать этот перебор под ковёр. Для большинства
современных программистов этого хватает.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39712627
Мимопроходящий
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
03.10.2018 18:43, aXS_new пишет:
> Можно ли создать объект по типу, записанному в строке?

можно конечно.
но все возможные классы которые ты попытаешься создать должны быть зарегистрированы в аппликации.
почитай про Class of... и как его едят.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39712633
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Можно, так работает сериализация/десериализация
Код: pascal
1.
2.
3.
4.
5.
var
  s: string;
begin
  s := 'Unit1.TForm1';
  TRttiContext.Create.FindType(s).GetMethod('Create').Invoke(блабла)


Естественно надо понимать что конструкторов может быть несколько, поэтому такие дела лучше указывать через атрибуты, например какой конструктор будет использоваться при автоматическом создании, чтобы автоматически подставить параметры.
Из нюансов требуется полный путь к типу, т.е. с указанием имени модуля.
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39712658
aXS_new
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
X-Cite , вот именно десериализацию и пытаюсь сделать. Но проблема такая: есть поле типа "TList<TMyClass>", и параметр className (получаю через TRttiContext) содержит такую строку: "TList<main.TMyClass>", вот и думаю, как, во-первых, все это преобразовать в TList<TMyClass> и, во-вторых, записать в него полученные из сериализованной строки объекты класса "TMyClass".
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39712659
rgreat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Опять люди свой компилятор пишут.

И зачем все так усложнять?
Неужели перебором из N вариантов классов сделать было нельзя?

Работать будет проще, предсказуемей и надежней.
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39712667
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aXS_new X-Cite , вот именно десериализацию и пытаюсь сделать. Но проблема такая: есть поле типа "TList<TMyClass>", и параметр className (получаю через TRttiContext) содержит такую строку: "TList<main.TMyClass>", вот и думаю, как, во-первых, все это преобразовать в TList<TMyClass> и, во-вторых, записать в него полученные из сериализованной строки объекты класса "TMyClass".
Зачем преобразовывать?
Для сериализации корректно указывать полные имена классов - через имя модуля.
Т.к. в разных модулях (читай неймспейсах) могут быть классы с одинаковым именованием. Откуда десериализатору узнать какой использовать без указания модуля (неймспейса)
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39712686
Valery_B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aXS_new,

Создай
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
type
 TMyClass = class(TObject)
 end;

 TCustomClass = class of TObject;
...
RegisteredClasses:=TDictionary<string,TCustomClass>.Create(TIStringComparer.Ordinal);
RegisteredClasses.Add('TMyClass',TMyClass);
...
MyInstance:=RegisteredClasses['TMyClass'].Create;
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39712704
aXS_new
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Всем спасибо за помощь, понемногу разбираюсь.

X-Cite , есть одна проблема. Пишу так:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
TMyClass = class
	str: string;
end;

...

var
	obj: TList<TMyClass>;

...

TRttiContext.create().findType('TList<Unit1.TMyClass>').getMethod('create').invoke(obj, []);



И при запуске программы появляется ошибка памяти "Access violation". Может быть, что-то не так делаю?
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39712734
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aXS_newВсем спасибо за помощь, понемногу разбираюсь.

X-Cite , есть одна проблема. Пишу так:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
TMyClass = class
	str: string;
end;

...

var
	obj: TList<TMyClass>;

...

TRttiContext.create().findType('TList<Unit1.TMyClass>').getMethod('create').invoke(obj, []);



И при запуске программы появляется ошибка памяти "Access violation". Может быть, что-то не так делаю?

Если метод Create - это конструктор, то в Invoke надо передавать не экземпляр объекта, а класс.
т.к. у вас десериализация, то передавать явно TList<TMyClass> нельзя, надо через метаданные Rtti как ниже...

Код: pascal
1.
2.
3.
4.
5.
var
  Rt: TRttiType;
...
Rt := TRttiContext.create().findType('TList<Unit1.TMyClass>');
obj := Rt.getMethod('create').invoke(Rt.AsInstance.MetaclassType, []).AsObject;



Естественно надо везде делать 100500 проверок, есть ли метод, конструктор ли он, вернулось ли значение, найден ли тип и т.д.
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39712736
andreymx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aXS_newВсем спасибо за помощь, понемногу разбираюсь.

X-Cite , есть одна проблема. Пишу так:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
TMyClass = class
	str: string;
end;

...

var
	obj: TList<TMyClass>;

...

TRttiContext.create().findType('TList<Unit1.TMyClass>').getMethod('create').invoke(obj, []);




И при запуске программы появляется ошибка памяти "Access violation". Может быть, что-то не так делаю?радуйся, тебе повезло
что свалилось сегодня у тебя, а не завтра у пользователя
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39712803
aXS_new
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
X-Cite , спасибо. Но проблема еще и в том, что "asObject" возвращает объект класса "TObject", и компилятор выдает ошибку: "Incompatible types".
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39712807
DimaBr
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aXS_newМожно ли создать объект по типу, записанному в строке?
Можно, собственно так всё и работает. По тексту их DFM создаётя форма и все компоненты на ней.
Курить TReader.ReadComponent до просветления и забыть про бесовщину - TRttiContext
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39712810
aXS_new
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
DimaBr , буду благодарен за разъяснения по поводу греховности использования TRttiContext.
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39712842
DimaBr
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Контекстов до Delphi 2010 этого не существовало.
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39712846
Фотография Dimonka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DimaBraXS_newМожно ли создать объект по типу, записанному в строке?
Можно, собственно так всё и работает. По тексту их DFM создаётя форма и все компоненты на ней.
Курить TReader.ReadComponent до просветления и забыть про бесовщину - TRttiContext
Не надо боятся RTTI.
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39712896
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aXS_new X-Cite , спасибо. Но проблема еще и в том, что "asObject" возвращает объект класса "TObject", и компилятор выдает ошибку: "Incompatible types".
Если у вас переменная obj конкретного типа, то тогда вместо AsObject, AsType<TList<TMyClass>>()
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39712911
aXS_new
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
X-Cite , но тип-то записан в строке, таким образом сделать не получится.
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39712928
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aXS_new X-Cite , но тип-то записан в строке, таким образом сделать не получится.
Так он же переменную объявил как-то...
Если он ее объявил как
var
obj: TList<TMyClass>
значит в этом контексте кода он знает про него.
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39712964
aXS_new
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
X-Cite , в том и дело, что переменная в моем случае - свойство класса, к которому обращаюсь через rtti, и таких свойств может быть много, а имена типов считываются в строку. То есть, написать "TList<TMyClass>" не могу, так как на этом месте может быть стоять и любой другой тип: "TMyClass", "TMyClass2", "TList<TMyClass2>" и т.д.
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39713007
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aXS_new X-Cite , в том и дело, что переменная в моем случае - свойство класса, к которому обращаюсь через rtti, и таких свойств может быть много, а имена типов считываются в строку. То есть, написать "TList<TMyClass>" не могу, так как на этом месте может быть стоять и любой другой тип: "TMyClass", "TMyClass2", "TList<TMyClass2>" и т.д.
Так а в чем проблема через Rtti в свойство записать значение?
Код: pascal
1.
2.
3.
MainObj := TRttiContext.Create().FindType('TMain').GetMethod('Create').Invoke(obj, []).AsObject;
Value := TRttiContext.Create().FindType('TMyClass').GetMethod('Create').Invoke(obj, []);
TRttiContext.Create.FindType('TMain').GetProperty('Obj').SetValue(MainObj, Value);
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39713197
aXS_new
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
X-Cite , проблема в том, что типы данных могут быть разными, в том числе, и "составными". Вот, как пример:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
TMyClass = class
	private
		FA: TClassA;
		FB: TClassB;
		FC: TList<TClassC>;
	published
		property A: TClassA read...
		...
end;



По этому классу прохожу при помощи rtti. Допустим, с простыми свойствами дела обстоят лучше, можно обратиться к их конструктору при помощи описанного вами метода.

А со свойством "FC: TList<TClassC>" как раз, трудности. Сначала нужно создать сам объект: TList<TClassC>, затем - в цикле записать в него элементы: FC[i]: TClassC.

Вы привели много хорошего кода, но как сделать это, я так и не понял. В итоге, в любом случае, наталкиваемся на то, что имя класса доступно только в строковом виде, а ситуация требует указателя на тип. Если подскажете, как это реализовать применительно к моему примеру, буду очень благодарен.
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39713217
DimaBr
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ЖЕСТЬ !!!
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39713222
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aXS_newа имена типов считываются в строкуА зачем вы так делаете? Работайте с TRttiType
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39713228
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
вот за 10 минут на коленке набросал... конечно надо делать все красиво с кешированием типов, объектов, узлов xml и т.п. чтобы не вычислять их каждый раз... Но для понимания сути достаточно...

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
  TClassA = class
  private
    FInt: Int32;
    FLong: Int64;
  end;

  TClassB = class
  private
    FStr: string;
  end;

  TMyClass = class
  private
    FA: TClassA;
    FB: TClassB;
  end;



Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    function ConvertVariantToValue(const aValue: Variant; aRttiType: TRttiType): TValue;
    procedure FillField(aObject: TObject; aTypeInfo: PTypeInfo; aNode: IXMLNode);
    function CreateClass(aNode: IXMLNode; aTypeInfo: PTypeInfo): TValue;
  public
    function Deserialize<T>(aNode: IXMLNode): T;
  end;

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
var
  Obj: TMyClass;
begin
  Obj := Deserialize<TMyClass>(LoadXMLData('<TMyClass><FA><FInt>5</FInt><FLong>8</FLong></FA><FB><FStr>asd</FStr></FB></TMyClass>').DocumentElement);
  // В Obj будет экземпляр нашего класса.
end;

function TForm1.ConvertVariantToValue(const aValue: Variant; aRttiType: TRttiType): TValue;
var
  Temp: Variant;
  Value: TValue;
begin
  TValue.Make(nil, aRttiType.Handle, Value);
  Temp := Value.AsVariant();
  Temp := VarAsType(aValue, TVarData(Temp).VType);
  Exit(TValue.FromVariant(Temp));
end;

function TForm1.CreateClass(aNode: IXMLNode; aTypeInfo: PTypeInfo): TValue;
begin
  Exit(TRttiContext.Create().GetType(aTypeInfo).AsInstance.MetaclassType.Create());
end;

function TForm1.Deserialize<T>(aNode: IXMLNode): T;
var
  Value: TValue;
begin
  Value := CreateClass(aNode, TypeInfo(T));
  FillField(Value.AsObject(), TypeInfo(T), aNode);
  Exit(Value.AsType<T>());
end;

procedure TForm1.FillField(aObject: TObject; aTypeInfo: PTypeInfo; aNode: IXMLNode);
var
  Rt: TRttiInstanceType;
  Rf: TRttiField;
  Value: TValue;
  Value2: TValue;
begin
  Rt := TRttiContext.Create().GetType(aTypeInfo).AsInstance;
  for Rf in Rt.GetDeclaredFields() do
  begin
    case Rf.FieldType.TypeKind of
      TTypeKind.tkInteger,
      TTypeKind.tkInt64,
      TTypeKind.tkUString:
        begin
          Value := ConvertVariantToValue(aNode.ChildNodes.FindNode(Rf.Name).NodeValue, Rf.FieldType);
        end;
      TTypeKind.tkClass:
        begin
          Value := CreateClass(aNode.ChildNodes.FindNode(Rf.Name), Rf.FieldType.Handle);
          FillField(Value.AsObject(), Rf.FieldType.Handle, aNode.ChildNodes.FindNode(Rf.Name));
        end;
    end;
    Rf.SetValue(aObject, Value);
  end;
end;

...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39713235
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Валяется у меня где-то на коленке сериализатор/десериализатор с поддержкой кастомных именований, регистрацией собственных преобразователей типов и коллбеков при (де)сериализации и настроечными опциями как какой тип описывать, с поддержкой наследуемых классов и экземпляров дочерних типов в базовых и рекурсивными ссылками
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
  TT = (aa,zz,ss);
  TSet = set of TT;

  TA = class
  private
    FA: Int32;
    FB: Int64;
    FC: string;
    FD: TArray<Int32>;
  public
    constructor Create;
  end;

  [SerializePrefix('Test')]
  TTest = class
  public
    [SerializeName('Grow')]
    FGrow: Integer;
    FStr: TSet;
    FClass: TA;
    constructor Create;
  end;


Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
<Config xmlns:o1="System.TObject" xmlns:Test="MainForm.TTest">
  <Test:Grow>50</Test:Grow> 
  <Test:FStr TT.zz="True" /> 
  <Test:FClass xmlns:a1="MainForm.TA">
    <a1:FA>100</a1:FA> 
    <a1:FB>200</a1:FB> 
    <a1:FC>asdfiuas89fh</a1:FC> 
    <a1:FD>
      <I0>10</I0> 
      <I1>20</I1> 
      <I2>30</I2> 
      <I3>40</I3> 
    </a1:FD>
  </Test:FClass>
</Config>
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39713252
X-Cite,

почему "true" ?

Код: pascal
1.
  <Test:FStr TT.zz="True" /> 



а не

Код: pascal
1.
  <Test:FStr TT="zz" /> 
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39713260
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
чччччччччч,

Потому, что у него множество
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39713261
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ччччччччччX-Cite,

почему "true" ?

Код: pascal
1.
  <Test:FStr TT.zz="True" /> 



а не

Код: pascal
1.
  <Test:FStr TT="zz" /> 


Множество. Через атрибут задаются значения который входят в него.
Есть опция для множества, писать все элементы через значения True/False (False - не входит) или оставлять только True
...
Рейтинг: 0 / 0
Cоздать объект по типу, записанному в строке
    #39713911
aXS_new
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
X-Cite , еще раз спасибо за помощь, во всем разобрался. Только что дописал класс благодаря вашим подсказкам.
...
Рейтинг: 0 / 0
30 сообщений из 30, показаны все 2 страниц
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Cоздать объект по типу, записанному в строке
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]