Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > [ "Начинающим" ]
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 17.05.2023, 11:39
bubaeshka bubaeshka вне форума
Прохожий
 
Регистрация: 20.02.2016
Сообщения: 13
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию Возврат списка строк из геттера класса. Как вернуть TStrings и присвоить его в Memo1

Продолжаю "вспоминать"/осваивать профильную специальность к своей недалёкой старости...

Возник вопрос. В поле класса, есть TStringList со служебными данными. Так как, просто закинуть присваиванием (как я когда то делал, ужас!) в поле MemoX.Lines этот стринглист является нежелательным, ибо нарушает великий принцип инкапсуляции! Решил немного извернутся. Долгое (относительно, для такого вопроса) гугленье дало некоторое решение.

Имеем класс:

Код:
  TBvn = class
  private
    firstLine:String;
    BVInfo:TStringList;
    Items:TObjectList<TBvnItem>;
  public
    constructor Create(filename:TFileName; IMaxFileRecords:Integer); //парсинг данных
    destructor Destroy; override;
    function getFirstLine:String;
    procedure getBVInfo(sll:TStrings);
  end;

Хотим отобразить на экране содержимое BVInfo, для этого такая процедурка:

Код:
procedure TBVN.getBVInfo(sll: TStrings);
begin
  if assigned(BVInfo) then sll.Assign(BVInfo);
end;

и вот такая проверка поведения в этой процедуре:

Код:
//для проверки - удалить
  if Assigned(BVN) then begin
    Memo1.Lines.Add(BVN.getFirstLine);
    BVN.getBVInfo(Memo2.Lines);
    Memo2.Lines[1]:='борода';
    BVN.getBVInfo(Memo2.Lines);
  end;
end;

Собственно, есть два вопроса:

1. Как ни странно, содержимое Memo не меняется. Это был такой эксперимент. Получается что процедура sll.Assign(BVInfo), копирует данные BVInfo из класса, в Memo, а не передаёт по ссылке? Ведь если бы шла передача по ссылке, а не по значению, то изменением второй строки Memo, в виде Memo2.Lines[1]:='борода', изменилось бы и поле BVInfo класса. Ну и нарушился бы принцип инкапсуляции соответственно. Или бы выскочила ошибка доступа какая-нибудь, потому что BVInfo в секции private. Но как ни странно, поведение всей этой конструкции именно такое, как мне надо, и работает именно так, как я хочу. Странно. Может кто-нибудь объяснить поведение?

2. Я вообще кучу всего передумал, и возврат массивом строк, и копирование в разные стринглисты перебором в цикле, через Add. Насколько неверно моё решение?

З.Ы. маленький: нужен ли перед некийStringList.Free, некийStringList.Clear ?
Ответить с цитированием
  #2  
Старый 17.05.2023, 18:35
rand rand вне форума
Прохожий
 
Регистрация: 12.05.2023
Адрес: Томск
Сообщения: 2
Версия Delphi: Delphi 11
Репутация: 10
По умолчанию

Цитата:
Сообщение от bubaeshka
1. Как ни странно, содержимое Memo не меняется. Но как ни странно, поведение всей этой конструкции именно такое, как мне надо, и работает именно так, как я хочу. Странно. Может кто-нибудь объяснить поведение?

Что тут объяснять. по простому: StringList.Assign копирует данные из источника. Да и любой .Assign по хорошему так должен делать.


Цитата:
Сообщение от bubaeshka
2. Я вообще кучу всего передумал, и возврат массивом строк, и копирование в разные стринглисты перебором в цикле, через Add. Насколько неверно моё решение?

А это смотря что нужно. Тут же свобода творчества :-)

Цитата:
Сообщение от bubaeshka
З.Ы. маленький: нужен ли перед некийStringList.Free, некийStringList.Clear ?

Здесь не нужен. По "правильному" каждый объект заботится о освобождении своих данных сам. И лучше написать
Код:
FreeAndNil(BVInfo);
Вместо StringList.Free
Ответить с цитированием
Этот пользователь сказал Спасибо rand за это полезное сообщение:
bubaeshka (18.05.2023)
  #3  
Старый 18.05.2023, 21:25
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,003
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Ну, если делать по правильному, то прямого доступа к внутреннему TStringList быть не должно, т.к.
1. Объект должен контролировать свои аттрибуты. Например, ты сохранил ссылку на StringList какого-то объекта у себя. Потом этот объект был удален. В лучшем случае при обращении по этой ссылке ты получишь AccessViolation, в худшем - будешь работать с неизвестно какими данными.
2. Та же ситуация, но в обратную сторону, ты взял ссылку на список в нескольких местах. Теперь если ты меняешь содержимое списка в одном месте, то оно меняеться во всех местах. Это тоже дает неожиданные сторонние эффекты.
И таких моментов может быть много.
Поэтому подобные поля прячут, а выставляют специальные свойства и методы, типа:
Код:
type
  TMyClass = class
  private
    FItems : TStringList;
    function GetCount : Integer;
    function GetItem(Index : Integer) : String;
    procedure SetItem(Index : Integer; Value : String);
    ...
  public
    constructor Create; virtual;
    destructor Destroy; override;

    function GetItemsAsList : TStringList;
    property Count : Integer read GetCount;
    property Items[Index : Integer] : String read GetItem write SetItem;
    ...
  end;

...

constructor TMyClass.Create;
begin
  inherited;
  FItems := TStringList.Create;
end;

destructor TMyClass.Destroy;
begin
  inherited;
  FItems.Free;
end;

function TMyClass.GetCount : Integer;
begin
  Result := FItems.Count;
end;

function TMyClass.GetItem(Index : Integer) : String;
begin
  Result := FItems[Index];
end;

procedure TMyClass.SetItem(Index : Integer; Value : String);
begin
  FItems[Index] := Value;
end;

// А вот тут создаем КОПИЮ и ее возвращаем
function TMyClass.GetItemsAsList : TSringList;
begin
  Result := TStringList.Create;
  Result.Assign(FItems);
end;

Ну там еще нужны функции типа Add, Delete, Remove, etc для работы с этим списком.

Последний раз редактировалось lmikle, 18.05.2023 в 21:33.
Ответить с цитированием
Этот пользователь сказал Спасибо lmikle за это полезное сообщение:
bubaeshka (22.05.2023)
  #4  
Старый 22.05.2023, 11:17
bubaeshka bubaeshka вне форума
Прохожий
 
Регистрация: 20.02.2016
Сообщения: 13
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Хм, интересно. Я вообще попробовал изначально вернуть TStringList результатом функции. Но у меня что то не пошло. Гугл дал ответ, мол передавайте в параметре ссылку на СтрингЛист, а не возвращайте его результатом.

Тут вот какой вопрос, ну сделаем мы так:

Код:
// А вот тут создаем КОПИЮ и ее возвращаем
function TMyClass.GetItemsAsList : TSringList;
begin
  Result := TStringList.Create;
  Result.Assign(FItems);
end;

А где же мы тогда будем убивать этот TStringList?

Я этот эксперимент специально затеял, чтобы проверить, как передаются значения, по ссылке или по значению? Потому что этого то я и боялся:

Цитата:
2. Та же ситуация, но в обратную сторону, ты взял ссылку на список в нескольких местах. Теперь если ты меняешь содержимое списка в одном месте, то оно меняеться во всех местах. Это тоже дает неожиданные сторонние эффекты.


Но! К моему удивлению, выяснилось, что функция

Код:
procedure TBVN.getBVInfo(sll: TStrings);
begin
  if assigned(BVInfo) then sll.Assign(BVInfo);
end;

Именно копирует содержимое внутреннего поля класса, во внутренний StringList, который был создан размещением на форме Memo.

И, так как в Delphi 7 это было не совсем так, меня это несколько удивило...
Ответить с цитированием
  #5  
Старый 23.05.2023, 02:19
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,003
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Да нет. Все правильно. Assign именно копирует содержимое списка, а не свм указатель или память. Так что да, можно передавать в виде параметра объект-контейнер, куда будет скопированно содержимое списка.
Не забывай, что любой объект в Delphi является указателем. Просто для простоты компилятор делает за тебя нужное раименование, так что "крышки" в коде расставлять не надо.
Ответить с цитированием
  #6  
Старый 23.05.2023, 05:07
bubaeshka bubaeshka вне форума
Прохожий
 
Регистрация: 20.02.2016
Сообщения: 13
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Я вообще как-то всегда пугался указателей. А тут выясняется, что я с ними и работаю всё время
Ответить с цитированием
  #7  
Старый 23.05.2023, 17:55
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,003
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Ну да, как-то так.
А что страшного в указателях? По сути, указатель, если брать аналогию, это бумажка, на которой написано в какой папке на какой полке лежит информация. Как в библиотеке - картотека и есть твои указатели на книги.
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 12:20.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter