Generyki, klasa w zmiennej

0

Cześć, mam taki problem. Mam metodę generyczną i funkcję, która na podstawie pewnych danych zwraca mi TClass:

 
var
   cType: TClass;
begin
  cType:=GetClassType(parameters);
end;

I teraz pytanie jest takie. Czy mogę w jakiś sposób dynamicznie wskazać typ generyczny w funkcji? Coś w sensie:

  Foo<cType>();  

Czy jest w ogóle jakikolwiek taki mechanizm?

0

O ile dobrze cię zrozumiałem, do nie da się dynamicznie typować parametrów metod. Delphi to strong typing, ale zawsze może w owej metodzie sprawdzić co trzeba i rzucić odpowiednim wyjątkiem.

Jest mechanizm ograniczeń w typach generycznych (podobny do tego z C#) więcej o Constraints in Generics
A używa się tego tak:

 
interface
type
  TMyClass = class
  public
    function Foo<T: class>(const AClass: T): T;
  end;

implementation

function TMyClass.Foo<T>(const AClass: T): T;
begin
  // coś tam ze zmienną AClass, która jest typu T z ograniczeniem do klasy
end;

Ograniczenie możesz zawęzić do konkretnego typu klasowego (ale nie tylko klasy, szczegóły w manualu) czyli deklaracja metody Foo może wyglądać tak:

type
  TMyClass = class
  public
    function Foo<T: TComponent>(const AClass: T): T;
  end;

A używa się tego normalnie jak metody, czyli:

  // to wykona się poprawnie
  Foo(TComponent(ASomeObject)); 

  // a tu dostaniesz błąd na etapie okmpilacji
  Foo('string!'); 
0

Chcę zrobić coś w stylu fabryki obiektów. Ale nie chcę dla każdego obiektu tworzyć oddzielnej metody. Chyba jednak posłużę się RTTI.

1

Można za pomocą RTTI, ale nie trzeba.
Jakiego rodzaju są to obiekty?
Od dawna używam fabryki dla formularzy w Delphi, durnowata (dummy) implementacja takiej fabryki była dołączona do mojego wykładu ze zlotu programistów Delphi o AnyDAC (2008 rok? czy jakoś tak ;-))
Generalnie sprowadza się to do kilku elementów:

  1. Klasa musi dziedziczyć z TPersistent
  2. Klasa musi być zarejestrowana za pomocą RegisterClass(TypKlasowy)

A używa się tego tak:

// rejestracja klasy 
RegisterClass(TMyClass);

// pobieranie klasy i kreowanie obiektu
var
  lClass : TPerstistentClass;
  lObject : TPersistent;
begin
  lClass := GetClass('TMyClass');
  if lClass <> nil then
    lObject := lClass.Create;
end;

I w sumie to wszystko.

0

Tak wiem, wszystko rozbija się o to, że to nie są klasy TPersistent. Wywodzą się bezpośrednio z TObject. Myślałem nad utworzeniem własnego mechanizmu rejestracji analogicznego do RegisterClass, ale z RTTI było szybciej, bo to tylko kilka linijek kodu.

0

W Delphi dla fabryki nie trzeba żadnych generyków:

function Make(AType:TClass):TObject;
begin
  Result:=AType.Create();
end;
0

Tak, ale to właśnie nie jest żadna fabryka - ten kod wymaga typu klasowego, wpisanego literalnie z kodu do którego masz dostęp.
RTTI pozwoli tworzyć dowolny typ obiektu, znając jego nazwę lub cokolwiek, co pozwoli go jednoznacznie zidentyfikować (oczywiście potrzebny będzie jakiś mechanizm rejestracji klasy, może być własny, mogą to być cale metadane opisujące klasę i sposób jej kreacji).
Poza tym, jak ten kod poradzi sobie z konstruktorem z parametrami? Nie poradzi sobie.
Osobiście zrozumiałem, że Juhasowi zależy na mechanizmie podobnym do refleksji - ale tego nie wiem.

0

Nie, nie musi być literalnie.
Może być ze zmiennej:

var T:TClass;
T:=TStringList;
Make(T);

Albo wręcz z innego obiektu:

bmp2:=Make(bmp.ClassType);
0

Maaatko... niech będzie, a więc tak: "[...] ten kod wymaga typu klasowego, wpisanego literalnie z kodu lub przekazanego przez zmienną, do którego masz dostęp (typu klasy) w miejscu użycia."
Teraz lepiej? A co to ma wspólnego z refleksją i fabryką? Nic.

PS. Na tym forum zawsze takie przedszkolne rozmowy odchodzą?

1 użytkowników online, w tym zalogowanych: 0, gości: 1