![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
#1
|
|||
|
|||
|
Продолжаю "вспоминать"/осваивать профильную специальность к своей недалёкой старости...
Возник вопрос. В поле класса, есть 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
|
|||
|
|||
|
Цитата:
Что тут объяснять. по простому: StringList.Assign копирует данные из источника. Да и любой .Assign по хорошему так должен делать. Цитата:
А это смотря что нужно. Тут же свобода творчества :-) Цитата:
Здесь не нужен. По "правильному" каждый объект заботится о освобождении своих данных сам. И лучше написать Код:
FreeAndNil(BVInfo); |
| Этот пользователь сказал Спасибо rand за это полезное сообщение: | ||
bubaeshka (18.05.2023)
| ||
|
#3
|
|||
|
|||
|
Ну, если делать по правильному, то прямого доступа к внутреннему 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
|
|||
|
|||
|
Хм, интересно. Я вообще попробовал изначально вернуть TStringList результатом функции. Но у меня что то не пошло. Гугл дал ответ, мол передавайте в параметре ссылку на СтрингЛист, а не возвращайте его результатом.
Тут вот какой вопрос, ну сделаем мы так: Код:
// А вот тут создаем КОПИЮ и ее возвращаем function TMyClass.GetItemsAsList : TSringList; begin Result := TStringList.Create; Result.Assign(FItems); end; А где же мы тогда будем убивать этот TStringList? Я этот эксперимент специально затеял, чтобы проверить, как передаются значения, по ссылке или по значению? Потому что этого то я и боялся: Цитата:
Но! К моему удивлению, выяснилось, что функция Код:
procedure TBVN.getBVInfo(sll: TStrings); begin if assigned(BVInfo) then sll.Assign(BVInfo); end; Именно копирует содержимое внутреннего поля класса, во внутренний StringList, который был создан размещением на форме Memo. И, так как в Delphi 7 это было не совсем так, меня это несколько удивило... |
|
#5
|
|||
|
|||
|
Да нет. Все правильно. Assign именно копирует содержимое списка, а не свм указатель или память. Так что да, можно передавать в виде параметра объект-контейнер, куда будет скопированно содержимое списка.
Не забывай, что любой объект в Delphi является указателем. Просто для простоты компилятор делает за тебя нужное раименование, так что "крышки" в коде расставлять не надо. |
|
#6
|
|||
|
|||
|
Я вообще как-то всегда пугался указателей. А тут выясняется, что я с ними и работаю всё время
![]() |
|
#7
|
|||
|
|||
|
Ну да, как-то так.
А что страшного в указателях? По сути, указатель, если брать аналогию, это бумажка, на которой написано в какой папке на какой полке лежит информация. Как в библиотеке - картотека и есть твои указатели на книги. |