Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
 Тип параметра метода, и работа с этим параметртром внутри метода без повторения кода  [new]
harisma
Member

Откуда:
Сообщений: 243
Здравствуйте. Такой вопрос.
Хочу реализовать метод в своем классе, который одним из параметров принимал бы или TDBGrid или TCRDBGrid (по крайней мере, пока эти 2 типа). Знаю, что оба класса порождены от TCustomDBGrid. И собственно на этом можно было бы и остановиться, объявив тип этого параметра как TCustomDBGrid, но тогда возникает вопрос, как красиво с этим объектом внутри метода работать? То есть, вызываю я это метод в программе, передавая в него или один или другой грид. А вот дальше как быть? У TCustomDBGrid я ко многим методам не имею доступа, в частности к тем, какие у него объявлены в секции protected. ОбЪявлять внутри метода внутренние переменные нужных типов и делать приведение типов входного параметра - тоже как-то не хочется, ибо код для этих разных типов гридов по сути тот же самый (вызываю те же самые методы и свойства), потому не хотелось бы делать повторение кода. Осознаю, что можно было бы сделать перегрузку этого метода (создать 2 метода с разными типами параметров) - но это опять таки повторение кода.
Существует ли способ, сделать это красиво? И если да, то как? Заранее благодарю за ответ.
29 апр 19, 10:57    [21874025]     Ответить | Цитировать Сообщить модератору
 Re: Тип параметра метода, и работа с этим параметртром внутри метода без повторения кода  [new]
wadman
Member

Откуда: Санкт-Петербург
Сообщений: 26142
Это не описание задачи, а, возможно, не лучшее её решение.

Без примера кода это будет лишь философствование на тему...
29 апр 19, 11:07    [21874037]     Ответить | Цитировать Сообщить модератору
 Re: Тип параметра метода, и работа с этим параметртром внутри метода без повторения кода  [new]
harisma
Member

Откуда:
Сообщений: 243
wadman
Это не описание задачи, а, возможно, не лучшее её решение.

Без примера кода это будет лишь философствование на тему...


Ок.
Вот пример кода:
+
procedure TMyWrapper.InternalExportCRDBGridData(ADBGrid: TCRDBGrid; WS: OleVariant;
  AAllColumn: Boolean = False; AOnlyCurrentRow: Boolean = False);
var
  col, row: Integer;
  sline: string;
begin
  sline := '';
  // add the info for the column names
  for col := 0 to ADBGrid.FieldCount - 1 do
    if ADBGrid.Columns[col].Visible or AAllColumn then
      sline := sline + ADBGrid.Columns[col].Title.Caption + #9;

  FMemo.Lines.Add(sline);

  // get the data into the memo
  if not AOnlyCurrentRow then
    for row := 0 to ADBGrid.DataSource.DataSet.RecordCount - 1 do
    begin
      sline := '';
      for col := 0 to ADBGrid.FieldCount - 1 do
        if ADBGrid.Columns[col].Visible or AAllColumn then
          sline := sline + ADBGrid.Fields[col].AsString + #9;
      sline := StringReplace(StringReplace(StringReplace(sline, #13#10, ' ', [rfReplaceAll]), #13, ' ', [rfReplaceAll]), #10, ' ', [rfReplaceAll]);
      ADBGrid.DataSource.DataSet.Next;
      FMemo.Lines.Add(sline);
    end
  else
  begin
    sline := '';
    for col := 0 to ADBGrid.FieldCount - 1 do
      if ADBGrid.Columns[col].Visible or AAllColumn then
        sline := sline + ADBGrid.Fields[col].AsString + #9;
    sline := StringReplace(StringReplace(StringReplace(sline, #13#10, ' ', [rfReplaceAll]), #13, ' ', [rfReplaceAll]), #10, ' ', [rfReplaceAll]);
    FMemo.Lines.Add(sline);
  end;
  ........... 
end;

procedure TMyWrapper.InternalExportDBGridData(ADBGrid: TDBGrid; WS: OleVariant;
  AAllColumn: Boolean = False; AOnlyCurrentRow: Boolean = False);
var
  col, row: Integer;
  sline: string;
begin
  sline := '';
  // add the info for the column names
  for col := 0 to ADBGrid.FieldCount - 1 do
    if ADBGrid.Columns[col].Visible or AAllColumn then
      sline := sline + ADBGrid.Columns[col].Title.Caption + #9;

  FMemo.Lines.Add(sline);

  // get the data into the memo
  if not AOnlyCurrentRow then
    for row := 0 to ADBGrid.DataSource.DataSet.RecordCount - 1 do
    begin
      sline := '';
      for col := 0 to ADBGrid.FieldCount - 1 do
        if ADBGrid.Columns[col].Visible or AAllColumn then
          sline := sline + ADBGrid.Fields[col].AsString + #9;
      sline := StringReplace(StringReplace(StringReplace(sline, #13#10, ' ', [rfReplaceAll]), #13, ' ', [rfReplaceAll]), #10, ' ', [rfReplaceAll]);
      ADBGrid.DataSource.DataSet.Next;
      FMemo.Lines.Add(sline);
    end
  else
  begin
    sline := '';
    for col := 0 to ADBGrid.FieldCount - 1 do
      if ADBGrid.Columns[col].Visible or AAllColumn then
        sline := sline + ADBGrid.Fields[col].AsString + #9;
    sline := StringReplace(StringReplace(StringReplace(sline, #13#10, ' ', [rfReplaceAll]), #13, ' ', [rfReplaceAll]), #10, ' ', [rfReplaceAll]);
    FMemo.Lines.Add(sline);
  end;
  ........... 
end;

А я хотел бы иметь вместо этих 2 фактически одинаковых методов, один, но который бы работал с обеими из этих типов гридов.

Сообщение было отредактировано: 29 апр 19, 11:41
29 апр 19, 11:15    [21874052]     Ответить | Цитировать Сообщить модератору
 Re: Тип параметра метода, и работа с этим параметртром внутри метода без повторения кода  [new]
Hammer
Member

Откуда: Москва
Сообщений: 488
harisma,
unit UMyWrapper;

interface

uses
...

type
  TMyWrapper = class  
...
    procedure TMyWrapper.InternalExportCRDBGridData(ADBGrid: TCustomDBGrid; WS: OleVariant;
  AAllColumn: Boolean = False; AOnlyCurrentRow: Boolean = False);
...
  end;

...

implementation

uses
...

type
  TCustomDBGridAccess = class(TCustomDBGrid);

...
procedure TMyWrapper.InternalExportCRDBGridData(ADBGrid: TCustomDBGrid; WS: OleVariant;
  AAllColumn, AOnlyCurrentRow: Boolean);
var
  col, row: Integer;
  sline: string;
begin
...
  col := TCustomDBGridAccess(ADBGrid).ProtectedProperty;
...
end
...
29 апр 19, 11:26    [21874079]     Ответить | Цитировать Сообщить модератору
 Re: Тип параметра метода, и работа с этим параметртром внутри метода без повторения кода  [new]
wadman
Member

Откуда: Санкт-Петербург
Сообщений: 26142
harisma,

можно передавать не grid, а связанный с ним dataset. Получится более универсально.
29 апр 19, 11:28    [21874082]     Ответить | Цитировать Сообщить модератору
 Re: Тип параметра метода, и работа с этим параметртром внутри метода без повторения кода  [new]
Кроик Семён
Member

Откуда: СПб --> Dortmund
Сообщений: 6569
harisma,

хочу дать небольшой комментарий к коду выше от Hammer'a

этот момент:
type
  TCustomDBGridAccess = class(TCustomDBGrid);


это такой легальный хак в Delphi, позволяющий получить доступ к protected-методам класса. Трюк: подобный хак-класс (TCustomDBGridAccess) должен быть объявлен в том же модуле, в котором будет использоваться. По-этому он в примере в секции IMPLEMENTATION, т.к. в INTERFACE не имеет смысла.

И, кстати, я бы назвал не TCustomDBGridAccess, а по аналогии со многими библиотеками, TCustomDBGridCracker (мое предпочтение) или TCustomDBGridHack
29 апр 19, 11:37    [21874092]     Ответить | Цитировать Сообщить модератору
 Re: Тип параметра метода, и работа с этим параметртром внутри метода без повторения кода  [new]
wadman
Member

Откуда: Санкт-Петербург
Сообщений: 26142
harisma
if not AOnlyCurrentRow then
    for row := 0 to ADBGrid.DataSource.DataSet.RecordCount - 1 do

Так не стоит делать, т.к. не все записи могут быть на клиенте в данный момент.

Как должно быть:
DataSet.First;
while not DataSet.Eof do begin
  DataSet.Next;
end;
29 апр 19, 11:39    [21874098]     Ответить | Цитировать Сообщить модератору
 Re: Тип параметра метода, и работа с этим параметртром внутри метода без повторения кода  [new]
Кроик Семён
Member

Откуда: СПб --> Dortmund
Сообщений: 6569
P.S.

и вот так этот хак используется:
   col := TCustomDBGridAccess(ADBGrid).ProtectedProperty
29 апр 19, 11:40    [21874101]     Ответить | Цитировать Сообщить модератору
 Re: Тип параметра метода, и работа с этим параметртром внутри метода без повторения кода  [new]
harisma
Member

Откуда:
Сообщений: 243
Кроик Семён, Hammer, wadman: Всем спасибо. Помогли вспомнить, ибо когда-то именно так и делал. (в смысле, создавал Кракед класс от предка, чтоб получить доступ к протектед методам). Один ньюанс - место объявления этого класса. Я его пытался объявлять ы секции interface - и не работало. Щас попробую ваш способ.
29 апр 19, 11:48    [21874112]     Ответить | Цитировать Сообщить модератору
 Re: Тип параметра метода, и работа с этим параметртром внутри метода без повторения кода  [new]
Hammer
Member

Откуда: Москва
Сообщений: 488
harisma
Кроик Семён, Hammer, wadman: Всем спасибо. Помогли вспомнить, ибо когда-то именно так и делал. (в смысле, создавал Кракед класс от предка, чтоб получить доступ к протектед методам). Один ньюанс - место объявления этого класса. Я его пытался объявлять ы секции interface - и не работало. Щас попробую ваш способ.

Не могет токого быть, правда если объявление было в том же модуле что и класс
29 апр 19, 12:01    [21874131]     Ответить | Цитировать Сообщить модератору
 Re: Тип параметра метода, и работа с этим параметртром внутри метода без повторения кода  [new]
white_nigger
Member

Откуда: Тула
Сообщений: 2209
Более красиво использовать класс-хелпер для доступа к протектед потрохам
29 апр 19, 18:54    [21874763]     Ответить | Цитировать Сообщить модератору
 Re: Тип параметра метода, и работа с этим параметртром внутри метода без повторения кода  [new]
wadman
Member

Откуда: Санкт-Петербург
Сообщений: 26142
white_nigger
Более красиво использовать класс-хелпер для доступа к протектед потрохам

Осталось только понять - зачем? Если смотреть на приведенный выше код.
30 апр 19, 07:40    [21875126]     Ответить | Цитировать Сообщить модератору
 Re: Тип параметра метода, и работа с этим параметртром внутри метода без повторения кода  [new]
kealon(Ruslan)
Member

Откуда: Нижневартовск
Сообщений: 5341
wadman
white_nigger
Более красиво использовать класс-хелпер для доступа к протектед потрохам

Осталось только понять - зачем? Если смотреть на приведенный выше код.
grid настройки для показа содержит(сильно не вникал что он там творит)

хелпер реально правильнее, приведения типов делают код потенциально опасным
30 апр 19, 10:59    [21875325]     Ответить | Цитировать Сообщить модератору
 Re: Тип параметра метода, и работа с этим параметртром внутри метода без повторения кода  [new]
Василий 2
Member

Откуда:
Сообщений: 800
1. Экспорт из грида не очень правильно, разумнее в самом деле обращаться сразу к датасету. Если какие-то вещи нужно брать от грида, можно их заранее извлечь (список выделенных записей, например) и передать параметром.
2. Два класса-потомка приводить насильно к общему знаменателю можно, но только если используемые методы виртуальные либо не перекрывались потомками (очевидно, но тем не менее).
3. Решение вполне имеет право на жизнь, но в дальнейшем может потребовать переделки (например, экспорт из другого источника, который не получится натянуть на общий глобус, или какие-то специфические фичи).
4. По приведенному коду - экспорт одной записи можно выделить в подпрограмму, чтобы не повторялся код, либо сделать один цикл и условие if OnlyCurrentRow then Break else Dataset.Next
13 май 19, 15:33    [21883510]     Ответить | Цитировать Сообщить модератору
 Re: Тип параметра метода, и работа с этим параметртром внутри метода без повторения кода  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11261
+
procedure TMyWrapper.InternalExportCRDBGridData(ADataSet: TDataSet; WS: OleVariant;
  AAllColumn: Boolean = False; AOnlyCurrentRow: Boolean = False);
var
  Fields: TList<TField>;
  col, row: Integer;
  sline: string;
begin
  Fields := TList<TField>.Create;
  try
    for col := 0 to ADataSet.FieldCount - 1 do begin
      if AAllColumn or ADataSet.Fields[col].Visible then
        Fields.Add(ADataSet.Fields[col]);
    end;
    if Fields.Count = 0 then
      Exit;

    sline := '';
    // add the info for the column names
    for col := 0 to Fields.Count - 1 do
      sline := sline + Fields[col].DisplayLabel + #9;
    FMemo.Lines.Add(sline);

    while not ADataSet.Eof do begin
      sline := '';
      for col := 0 to Fields.Count - 1 do
        sline := sline + Fields[col].Text+ #9;
      sline := StringReplace(StringReplace(StringReplace(sline, #13#10, ' ', [rfReplaceAll]), #13, ' ', [rfReplaceAll]), #10, ' ', [rfReplaceAll]);
      FMemo.Lines.Add(sline);
      if AOnlyCurrentRow then
        Break;
      ADataSet.Next;
    end;
  finally
    Fields.Free;
  end;
  ........... 
end;
13 май 19, 15:52    [21883532]     Ответить | Цитировать Сообщить модератору
 Re: Тип параметра метода, и работа с этим параметртром внутри метода без повторения кода  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11261
Василий 2
2. Два класса-потомка приводить насильно к общему знаменателю можно, но только если используемые методы виртуальные либо не перекрывались потомками
С какого перепугу?
13 май 19, 15:54    [21883536]     Ответить | Цитировать Сообщить модератору
 Re: Тип параметра метода, и работа с этим параметртром внутри метода без повторения кода  [new]
Василий 2
Member

Откуда:
Сообщений: 800
_Vasilisk_
Василий 2
2. Два класса-потомка приводить насильно к общему знаменателю можно, но только если используемые методы виртуальные либо не перекрывались потомками
С какого перепугу?

С большого.
Перекрыл ты в TChild невиртуальный метод Foo, а потом вызываешь TParent(Child).Foo, что получится? Правильно, ерунда
14 май 19, 10:20    [21884104]     Ответить | Цитировать Сообщить модератору
Все форумы / Delphi Ответить