Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Узнать наследника TList<> / 25 сообщений из 27, страница 1 из 2
17.05.2018, 16:58
    #39646264
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
Можно ли как-то узнать, что переданный объект является экземпляром класса или наследником TList<T>?

Если указать конкретный тип
Код: pascal
1.
2.
Obj := TList<Integer>.Create;
if Obj is TList<Integer> then

то все определяет. А мне бы узнать для произвольного типа
Код: pascal
1.
if Obj is TList<> then

Задача решается?


С уважением, Vasilisk
...
Рейтинг: 0 / 0
17.05.2018, 17:18
    #39646275
alekcvp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
_Vasilisk_,

Тут есть одна проблема, которая заключается в том что класса TList<T>, как такового, не существует. Существуют классы TList<Integer>, TList<Byte> и т.п., которые создаются при их первом использовании. Т.е. в операторе is экземпляр не с чем сравнивать.

Как вариант вижу такое извращение:
Код: pascal
1.
if Pos('TLIST<', AnsiUpperCase(List.ClassName)) = 1 then


Но тут могут быть нюансы: например, если в проекте есть несколько TList<>, объявленные в разных модулях - таким образом не получится отличать их друг от друга.
...
Рейтинг: 0 / 0
17.05.2018, 17:19
    #39646277
alekcvp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
А для наследника там вообще опа.
...
Рейтинг: 0 / 0
17.05.2018, 17:23
    #39646279
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
alekcvp,

Этот вариант я рассматривал. Все решается. И разные классы и наследники. Не хотелось со строками связываться
...
Рейтинг: 0 / 0
17.05.2018, 17:43
    #39646292
alekcvp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
_Vasilisk_,

Код: pascal
1.
2.
3.
4.
    List := TList<Integer>.Create;
    WriteLn(List.ClassName);
    WriteLn(List.ClassParent.ClassName);
    WriteLn(List.ClassParent.ClassParent.ClassName);

Код: plaintext
1.
2.
TList<System.Integer>
TEnumerable<System.Integer>
TObject
Не вижу других вариантов...
...
Рейтинг: 0 / 0
17.05.2018, 17:49
    #39646297
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
alekcvpНе вижу других вариантов...Вот так и сделал
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
function IsList(AObject: TObject): Boolean;
var
  LClass: TClass;
  LName: String;
  LPos: Integer;
begin
  LClass := AObject.ClassType;
  while LClass <> nil do begin
    if LClass.UnitName = TList<Byte>.UnitName then begin
      LName := LClass.ClassName;
      LPos := Pos('<', LName);
      if
        (LPos > 0) and
        (Pos('>', LName) = Length(LName)) and
        LName.StartsWith('TList')
      then begin
        Exit(True);
      end;
    end;
    LClass := LClass.ClassParent;
  end;
  Result := False;
end;
...
Рейтинг: 0 / 0
17.05.2018, 17:52
    #39646300
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
_Vasilisk_,

Даже вот так
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
function TJsonParser.IsList(AObject: TObject): Boolean;
var
  LClass: TClass;
  LName: string;
begin
  LClass := AObject.ClassType;
  while LClass <> nil do begin
    if LClass.UnitName = TList<Byte>.UnitName then begin
      LName := LClass.ClassName;
      if (Pos('>', LName) = Length(LName)) and LName.StartsWith('TList<') then
        Exit(True);
    end;
    LClass := LClass.ClassParent;
  end;
  Result := False;
end;



Вот это условие
Код: pascal
1.
Pos('>', LName) = Length(LName)

позволяет отбросить вложенные типы
...
Рейтинг: 0 / 0
17.05.2018, 17:56
    #39646302
alekcvp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
_Vasilisk_,

А почему недостаточно этого?
Код: pascal
1.
LName.StartsWith('TList<')
...
Рейтинг: 0 / 0
17.05.2018, 18:04
    #39646307
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
alekcvpА почему недостаточно этого?
Код: pascal
1.
LName.StartsWith('TList<')

Я же написал - можно нарваться на вложенные типы
Код: pascal
1.
TList<System.string>.TEnumerator
...
Рейтинг: 0 / 0
17.05.2018, 20:15
    #39646357
alekcvp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
_Vasilisk_,

Тогда уж заменить условие на:
Код: pascal
1.
if LName.StartsWith('TList<') and (LName[Length(LName)] = '>') then ...

это будет быстрее чем Pos().

Хотя мой вариант обломается на вложенном дженерике, а исходный - на чём-то вроде такого:
Код: pascal
1.
TList<TList<Integer>>

:)
...
Рейтинг: 0 / 0
17.05.2018, 21:07
    #39646375
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
alekcvpэто будет быстрее чем Pos().Можно обломаться на
Код: pascal
1.
TList<System.string>.TInnerType<System.Integer>

(да, сейчас такого нет, но все же)
alekcvp
Код: pascal
1.
TList<TList<Integer>>

Ценное замечание. Спасибо. Будем думать
...
Рейтинг: 0 / 0
17.05.2018, 21:40
    #39646384
white_nigger
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
alekcvpТогда уж заменить условие на:
Код: pascal
1.
if LName.StartsWith('TList<') and (LName[Length(LName)] = '>') then ...


это будет быстрее чем Pos().А если поменять операнды местами - то будет ещё быстрее :)
...
Рейтинг: 0 / 0
17.05.2018, 21:58
    #39646392
alekcvp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
white_niggerэто будет быстрее чем Pos().А если поменять операнды местами - то будет ещё быстрее :)[/quot]
Ну да, я исходил из того чтобы не обломаться на пустой строке, а тут она не может быть пустой...
...
Рейтинг: 0 / 0
17.05.2018, 23:31
    #39646420
kealon(Ruslan)
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
_Vasilisk_,

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
type
  Some = class helper for TObject
  public
    class function IsListOf<t>(): Boolean;
  end;

class function Some.IsListOf<t>(): Boolean;
begin
  Result := Self.InheritsFrom(TList<t>);
end;


Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
type
  TL = class(TList<Integer>);

procedure Test();
var
  d: TL;
begin
  d := TL.Create;
  try
    Writeln('<Integer>:', d.IsListOf<Integer>());
    Writeln('<Byte>:', d.IsListOf<Byte>());
  finally
    d.Free;
  end;
end;

...
Рейтинг: 0 / 0
18.05.2018, 09:27
    #39646525
makhaon
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
kealon(Ruslan),

хорошо :)
...
Рейтинг: 0 / 0
18.05.2018, 09:53
    #39646541
alekcvp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
kealon(Ruslan),

В т.з. стояла задача определить что класс - наследник TList<T> при неизвестном T.
...
Рейтинг: 0 / 0
18.05.2018, 09:56
    #39646545
kealon(Ruslan)
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
_Vasilisk_,

хе ..., под вечер работать нельзя
наверное только строками, компилятор даже не связанные ни с чем методы выделить в один не может

Код: 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.
type
  TL = class(TList<Integer>)
  private
    class function ErrorOffset(): Integer;
  end;
  Some = class helper for TObject
  private
    class function GetVMTProc(VMTProcIndex: Integer): Pointer;
  public
    class function IsList(): Boolean;
  end;

class function TL.ErrorOffset: Integer;
begin
  asm
    mov Result, vmtOffset Error
  end;
  Result := Result div SizeOf(Pointer);
end;

class function Some.GetVMTProc(VMTProcIndex: Integer): Pointer;
var
  p: pointer;
  VirtualMethodCount: word;
  m: PPointer;
begin
  p := PPointer(PByte(Self) + vmtMethodTable)^;
  VirtualMethodCount:= PWord(p)^;

  if VirtualMethodCount >= VMTProcIndex  then
    Exit(nil);

  m := Pointer(Self);
  inc(m, VMTProcIndex);
  Result := m^;
end;

class function Some.IsList(): Boolean;
type
  TP = procedure (const Msg: string; Data: NativeInt) of Object;
var
  v: TP;
  i: Integer;
  m: Pointer;
  c: TClass;
begin
  v := TL.Error;
  i := TL.ErrorOffset;
  c := Self;
  repeat
    m := c.GetVMTProc(i);
    if (m = nil) then
      Break;

    if TMethod(v).Code = m then
      Exit(True);
    c := c.ClassParent;
  until c = nil;
  Result := False;
end;


Код: pascal
1.
2.
3.
4.
5.
6.
procedure Test();
begin
  Writeln(TL.IsList);
  Writeln(TList<Byte>.IsList);
  Writeln(TList<Integer>.IsList);
end;



Код: plaintext
1.
2.
TRUE
FALSE
TRUE
...
Рейтинг: 0 / 0
18.05.2018, 14:53
    #39646754
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
kealon(Ruslan)
Код: pascal
1.
class function IsListOf<t>(): Boolean;

Так и я могу :)

Можно даже проще
Код: pascal
1.
if Obj is TList<Integer> then

ноalekcvpВ т.з. стояла задача определить что класс - наследник TList<T> при неизвестном T.
В общем было принято пожертвовать вариантом_Vasilisk_
Код: pascal
1.
TList<System.string>.TInnerType<System.Integer>

в виду отсутствия на сегодня у TList<> вложенных дженерик типов

И получилось так
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
function IsList(AObject: TObject): Boolean;
var
  LClass: TClass;
  LUnit: string;
  LName: string;
begin
  LClass := AObject.ClassType;
  LUnit := TList<Byte>.UnitName;
  while LClass <> nil do begin
    LName := LClass.ClassName;
    if
      (LName[Lenght(LName)] = '>') and
      (LClass.UnitName = LUnit) and
      LName.StartsWith('TList<')
    then
      Exit(True);
    LClass := LClass.ClassParent;
  end;
  Result := False;
end;
...
Рейтинг: 0 / 0
18.05.2018, 15:26
    #39646771
kealon(Ruslan)
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
_Vasilisk_,

а заем тебе это надо? просто для развития? или какая-то цель практическая есть?
...
Рейтинг: 0 / 0
18.05.2018, 15:29
    #39646773
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
kealon(Ruslan)а заем тебе это надо?Пишу свой велосипед по сериализации/десериализации. И хочу, чтобы TList<> сериализовался как массив
...
Рейтинг: 0 / 0
18.05.2018, 18:45
    #39646851
rgreat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
На, может поможет:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
function TArrayEx<T>.ToString(Delimeter: string): string;
var
  i : Integer;
  n : integer;
  s : string;
begin
  Result:='';
  for i:=Low to High do begin
    if (Result<>'') then begin
      s:=Delimeter+TValue.From<T>(Items[i]).ToString;
    end else begin
      s:=TValue.From<T>(Items[i]).ToString;
    end;

    n:=Length(Result);
    SetLength(Result,n+length(s));
    Move(s[1],Result[n+1],Length(s)*SizeOf(Char));
  end;
end;
...
Рейтинг: 0 / 0
18.05.2018, 21:41
    #39646916
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
rgreatНа, может поможет:Чем? Сериализатор я уже написал. Понятно, что если использовать свои классы, то можно сделать все, что угодно. Интересовало решение на стандартных. И именно детектирование стандартного класса
...
Рейтинг: 0 / 0
18.05.2018, 21:48
    #39646920
rgreat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
_Vasilisk_Чем? Кто тебя знает.

Например
Код: pascal
1.
TValue.From<T>(Items[i]).ToString;
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
27.11.2020, 15:38
    #40022799
Квейд
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
alekcvp
_Vasilisk_,

Тут есть одна проблема, которая заключается в том что класса TList<T>, как такового, не существует. Существуют классы TList<Integer>, TList<Byte> и т.п.
У нас дженерики, а не шаблоны. Код экземпляров TList<Integer> и TList<Byte> будет один и тот же. Так что, по сути, существует только TList<T>.
...
Рейтинг: 0 / 0
27.11.2020, 16:28
    #40022816
Kazantsev Alexey
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать наследника TList<>
Квейд
Код экземпляров TList<Integer> и TList<Byte> будет один и тот же. Так что, по сути, существует только TList<T>.

Это не так.
...
Рейтинг: 0 / 0
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Узнать наследника TList<> / 25 сообщений из 27, страница 1 из 2
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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