Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Cоздать объект по типу, записанному в строке / 25 сообщений из 30, страница 1 из 2
03.10.2018, 18:43
    #39712618
aXS_new
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cоздать объект по типу, записанному в строке
Можно ли создать объект по типу, записанному в строке? Что-то вроде

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



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

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

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


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

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

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

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
03.10.2018, 23:44
    #39712734
X-Cite
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cоздать объект по типу, записанному в строке
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
03.10.2018, 23:52
    #39712736
andreymx
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cоздать объект по типу, записанному в строке
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
04.10.2018, 09:48
    #39712803
aXS_new
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cоздать объект по типу, записанному в строке
X-Cite , спасибо. Но проблема еще и в том, что "asObject" возвращает объект класса "TObject", и компилятор выдает ошибку: "Incompatible types".
...
Рейтинг: 0 / 0
04.10.2018, 09:55
    #39712807
DimaBr
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cоздать объект по типу, записанному в строке
aXS_newМожно ли создать объект по типу, записанному в строке?
Можно, собственно так всё и работает. По тексту их DFM создаётя форма и все компоненты на ней.
Курить TReader.ReadComponent до просветления и забыть про бесовщину - TRttiContext
...
Рейтинг: 0 / 0
04.10.2018, 09:58
    #39712810
aXS_new
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cоздать объект по типу, записанному в строке
DimaBr , буду благодарен за разъяснения по поводу греховности использования TRttiContext.
...
Рейтинг: 0 / 0
04.10.2018, 10:39
    #39712842
DimaBr
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cоздать объект по типу, записанному в строке
Контекстов до Delphi 2010 этого не существовало.
...
Рейтинг: 0 / 0
04.10.2018, 10:45
    #39712846
Dimonka
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cоздать объект по типу, записанному в строке
DimaBraXS_newМожно ли создать объект по типу, записанному в строке?
Можно, собственно так всё и работает. По тексту их DFM создаётя форма и все компоненты на ней.
Курить TReader.ReadComponent до просветления и забыть про бесовщину - TRttiContext
Не надо боятся RTTI.
...
Рейтинг: 0 / 0
04.10.2018, 11:48
    #39712896
X-Cite
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cоздать объект по типу, записанному в строке
aXS_new X-Cite , спасибо. Но проблема еще и в том, что "asObject" возвращает объект класса "TObject", и компилятор выдает ошибку: "Incompatible types".
Если у вас переменная obj конкретного типа, то тогда вместо AsObject, AsType<TList<TMyClass>>()
...
Рейтинг: 0 / 0
04.10.2018, 12:09
    #39712911
aXS_new
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cоздать объект по типу, записанному в строке
X-Cite , но тип-то записан в строке, таким образом сделать не получится.
...
Рейтинг: 0 / 0
04.10.2018, 12:34
    #39712928
X-Cite
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cоздать объект по типу, записанному в строке
aXS_new X-Cite , но тип-то записан в строке, таким образом сделать не получится.
Так он же переменную объявил как-то...
Если он ее объявил как
var
obj: TList<TMyClass>
значит в этом контексте кода он знает про него.
...
Рейтинг: 0 / 0
04.10.2018, 13:14
    #39712964
aXS_new
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cоздать объект по типу, записанному в строке
X-Cite , в том и дело, что переменная в моем случае - свойство класса, к которому обращаюсь через rtti, и таких свойств может быть много, а имена типов считываются в строку. То есть, написать "TList<TMyClass>" не могу, так как на этом месте может быть стоять и любой другой тип: "TMyClass", "TMyClass2", "TList<TMyClass2>" и т.д.
...
Рейтинг: 0 / 0
04.10.2018, 14:13
    #39713007
X-Cite
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cоздать объект по типу, записанному в строке
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
04.10.2018, 18:20
    #39713197
aXS_new
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cоздать объект по типу, записанному в строке
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
04.10.2018, 18:51
    #39713217
DimaBr
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cоздать объект по типу, записанному в строке
ЖЕСТЬ !!!
...
Рейтинг: 0 / 0
04.10.2018, 18:57
    #39713222
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cоздать объект по типу, записанному в строке
aXS_newа имена типов считываются в строкуА зачем вы так делаете? Работайте с TRttiType
...
Рейтинг: 0 / 0
04.10.2018, 19:14
    #39713228
X-Cite
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cоздать объект по типу, записанному в строке
вот за 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
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Cоздать объект по типу, записанному в строке / 25 сообщений из 30, страница 1 из 2
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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