Например, у меня есть три класса (TMyClass1, TMyClass2 и TMyClass3).
У меня есть функция, которая принимает в качестве параметра строку с именем типа, а затем создает экземпляр этого класса с учетом типа. Прямо сейчас я использую операторы if, например:
if (AFormName = 'xxx1') then
begin
MyClass := MyClass1.Create;
end else if (AFormName = 'xxx2') then
begin
MyClass := MyClass2.Create;
end;
Так далее..
Есть ли способ сохранить тип в переменной, чтобы изменить ссылку на строки на типы и не использовать это?
Если это поможет, MyClass1, MyClass2 и MyClass3 наследуются от другого класса...
Например, type TMyTypeClass = class of TMyType; затем вы объявляете переменную var MyTypeClass: TMyTypeClass;, затем назначаете ее MyTypeClass := TMyClass1;, а затем фактически используете ее MyClass := MyTypeClass.Create();
И как мне связать строку с этой переменной типа?
Строки — это отдельная история. Вы не ссылаетесь по имени строки. Вы ссылаетесь на сам фактический тип. Почему вы хотите использовать строки для ссылки на классы? Возможно, вы сможете использовать RTTI, но это кажется излишним для такой простой задачи.
Используй словарь





Посмотрите на функции RTL RegisterClass() и FindClass()/GetClass(), они были разработаны именно для такого сценария, например:
interface
uses
..., Classes;
type
MyBase = class(TPersistent)
public
constructor Create; virtual;
end;
MyBaseClass = class of MyBase;
MyClass1 = class(MyBase)
public
constructor Create; override;
end;
MyClass2 = class(MyBase)
public
constructor Create; override;
end;
MyClass3 = class(MyBase)
public
constructor Create; override;
end;
...
function MakeMyClass(const Name: string): MyBase;
implementation
function MakeMyClass(const Name: string): MyBase;
begin
Result := MyBaseClass(GetClass(Name)).Create;
end;
...
initialization
RegisterClasses([MyClass1, MyClass2, MyClass3{, ...}]);
end.
Тогда вы можете сделать это:
var
MyObj: MyBase;
begin
MyObj := MakeMyClass('MyClass1');
...
MyObj.Free;
end;
Недостатком является то, что классы должны быть производными от TPersistent. Если вы не хотите использовать TPersistent или просто хотите использовать разные имена для создания объектов класса, не очень сложно настроить пользовательскую фабрику, например, с помощью TDictionary, например:
interface
type
MyBase = class
public
constructor Create; virtual;
end;
MyBaseClass = class of MyBase;
MyClass1 = class(MyBase)
public
constructor Create; override;
end;
MyClass2 = class(MyBase)
public
constructor Create; override;
end;
MyClass3 = class(MyBase)
public
constructor Create; override;
end;
...
function MakeMyClass(const Name: string): MyBase;
implementation
uses
System.Generics.Collections, System.SysUtils;
var
MyFactory: TDictionary<string, MyBaseClass>;
function MakeMyClass(const Name: string): MyBase;
begin
Result := MyFactory[Name].Create;
end;
...
initialization
MyFactory := TDictionary<string, MyBaseClass>.Create;
MyFactory.Add('xxx1', MyClass1);
MyFactory.Add('xxx2', MyClass2);
MyFactory.Add('xxx3', MyClass3);
finalization
MyFactory.Free;
end.
Тогда вы можете сделать это:
var
MyObj: MyBase;
begin
MyObj := MakeMyClass('xxx1');
...
MyObj.Free;
end;
Разве TMyBaseCreateFunc не должен быть вместо MyBaseClass?? Спасибо за вашу помощь.
@TomB Да, так и должно быть. Это остатки другой версии кода, где я использовал указатели на функции, создающие экземпляры объектов. Я исправил это в своем примере здесь, спасибо.
да. Это называется ссылкой на класс. (связь).