Я создаю очень грубый графический интерфейс для картографа модели, который в основном пересекает все поля TEdit и TMemo в форме, извлекает текст и устанавливает этот текст в объект модели данных.(Решение основано на предположительно хрупком подходе «соглашение о конфигурации», в котором сопоставляются только свойства в модели данных, имя которой совпадает с полем в форме.)
Отказ от ответственности: извините за пример раздутого кода.Здесь идет:
Форма.
{ Standard interface section above this line }
type
TfrmMain = class(TForm)
StringField1: TEdit;
StringField2: TMemo;
{ Other fields and procedures dropped for brevity }
private
procedure FillGUIFields();
end;
Модель данных.
TDataModel = class(TObject)
private
FStringField1: string;
FStringField2: string;
{ Getters and setters dropped for brevity }
public
property StringField1: string read GetFStringField1 write SetFStringField1;
property StringField2: string read GetFStringField2 write SetFStringField2;
end;
Реализация.
const
MAX_RUNS = 100;
procedure GUIToData(var AObject: TObject; const Form: TForm);
var
c: TRTTIContext;
t: TRTTIType;
prop: TRTTIProperty;
Component: TComponent;
Text: string;
i: integer;
begin
c := TRTTIContext.Create();
t := c.GetType(AObject.ClassType);
for prop in t.GetProperties do begin
Component := Form.FindComponent(prop.Name); // Naive "conv. over conf." matching
if (Component <> nil) then begin
if (Component is TEdit) then prop.SetValue(AObject, TValue.FromVariant(TEdit (Component).Text));
if (Component is TMemo) then prop.SetValue(AObject, TValue.FromVariant(TMemo(Component).Text));
end;
end;
c.Free();
end;
procedure TfrmMain.btnFetchToModelClick(Sender: TObject);
var
Data: TDataModel;
i: integer;
NumberOfExceptions: integer;
begin
NumberOfExceptions := 0;
for i := 0 to MAX_RUNS - 1 do begin
try
FillGUIFields();
Data := TDataModel.Create();
GUIToData(TObject(Data), self);
Data.Free();
except on E: EAccessViolation do
begin
Inc(NumberOfExceptions);
end;
end;
end;
MessageDlg('Number of runs: ' + IntToStr(MAX_RUNS) + #13#10 +
'Number of exceptions: ' + IntToStr(NumberOfExceptions), mtInformation, [mbOk], 0);
end;
function TDataModel.GetFStringField1: string;
begin
Result := FStringField1;
end;
procedure TDataModel.SetFStringField1(Value: string);
begin
FStringField1 := Value;
end;
{ Identical getter/setter for StringField2 }
procedure TfrmMain.FillGUIFields;
var
i: integer;
TempBuffer: string;
begin
TempBuffer := '';
Randomize();
for i := 0 to Random(16) - 1 do begin
if Random(2) = 0 then
TempBuffer := TempBuffer + Chr(Random(25) + 65)
else
TempBuffer := TempBuffer + Chr(Random(25) + 97);
end;
StringField1.Text := TempBuffer; // Filling the edit field
{ Identical code for filling the memo field }
end;
end.
Когда я запускаю этуЯ получаю исключение нарушения прав доступа в 27% случаев.Если я только устанавливаю свойство, соответствующее имени поля TEdit (т. Е. StringField1), исключений не возникает.Если я обращаюсь к полям напрямую (либо позволяя получателю / установщику указывать прямо на поля, либо используя t.GetFields в GUIToData-процедуре), нарушение доступа не выдается.
Могут ли люди это воспроизвести?Кто-нибудь знает, что вызывает это странное поведение?Спасибо!