Здравствуйте, Didi, Вы писали:
D>Привет всем. D>Народ напомните мне как имея имя свойства (строку с именем свойства) D>установить или считать его значение.
Примерно так:
Uses TypInfo,.....;
function IsPropertyInfo(Obj: TPersistent; PropertyName: string;
var PropInfo: PPropInfo): Boolean;
var TypeInfo: PTypeInfo;
begin
Result:=False;
TypeInfo:=Obj.ClassInfo;
if TypeInfo=nil then exit;
PropInfo:=GetPropInfo(TypeInfo, PropertyName);
if PropInfo=nil then exit;
Result:=True;
end;
Function PropertyExists(AObject:TPersistent; PropertyName:string):boolean;
var PropInfo:PPropInfo;
begin
Result:=IsPropertyInfo(AObject,PropertyName,PropInfo);
end;
function SetStringProperty(Obj: TPersistent; PropertyName: string; Value: string): Boolean;
var PropInfo: PPropInfo;
begin
Result:=IsPropertyInfo(Obj,PropertyName,PropInfo);
if not Result then exit;
SetStrProp(Obj,PropInfo,Value);
end;
function GetStringProperty(Obj: TPersistent; PropertyName: string): string;
var PropInfo: PPropInfo;
begin
Result:='';
if not IsPropertyInfo(Obj,PropertyName,PropInfo) then exit;
Result:=GetStrProp(Obj,PropInfo);
end;
// использованиеbegin
if PropertyExists(MyForm,'Caption') and GetStringProperty(MyForm,'Caption')='Old form caption'then
begin
if SetStringProperty(MyForm,'Caption','New form caption') then ShowMessage('Ok!')
else ShowMessage('Failed!');
end;
end;
Здравствуйте, Master Yoda, Вы писали:
MY>Здравствуйте, Jack128, Вы писали:
MY>>>Выводит пустую строку, а что? J>>А у меня выдало Test
MY>Хм, а какая версия Delphi? У меня пятая
в седьмой и 2006 — так как я описал. Собственно так было всегда, имхо у тя где то глючит
J>>Инициализация проводится только для локальных/глобальных переменных, но не для Result
MY>Мне казалось что к Result применимы те же правила, что и для локальных переменных. Т.е. это по сути неявная локальная переменная.
Нет, это не так. Result — это не явный var параметр. собственно посмотри на асм код двух таких подпрограмм:
procedure Proc(var Result: string; I, J: Integer);
begin
Result := IntToStr(I) + IntToStr(J)
end;
function Func(I, J: Integer): string;
begin
Result := IntToStr(I) + IntToStr(J)
end;
procedure TForm8.FormCreate(Sender: TObject);
var
S: string;
begin
Proc(S, 1, 2);
S := Func(1, 2);
Caption := s;
end;
он абсолютно одинаков.
J>>ЗЫ Ты точно закоментировал строку Result := '' ??
MY>Да.
DM>> if not IsPropertyInfo(Obj,PropertyName,PropInfo) then exit;
DM>> Result:=GetStrProp(Obj,PropInfo);
DM>>end;
DM>>
MY>Хотя допускаю, что может это такой coding-style маниакальный
Сорри что тоже не по теме. Инициализация НЕлишняя.
Вы будете смеятся но:
function GetString: string;
begin
Exit;
end;
var
s: string;
begin
s := 'Master Yoda';
s := GetString;
ShowMessage(s); // s is equal to 'Master Yoda'; s is not emptyend;
Здравствуйте, Didi, Вы писали:
D>Привет всем. D>Народ напомните мне как имея имя свойства (строку с именем свойства) D>установить или считать его значение.
См. функции из TypInfo:
GetOrdProp
SetOrdProp
GetStrProp
SetStrProp
...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
It is always bad to give advices, but you will be never forgiven for a good one.
Oscar Wilde
Здравствуйте, Didi, Вы писали:
D>Спасибо за подробный ответ. D>И еще вопрос, можно получить тип D>определенного свойства (т.е. строка, объект, целое число и пр.)
Функция PropType все из того же модуля:
function PropType(AClass: TClass; const PropName: string): TTypeKind;
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
It is always bad to give advices, but you will be never forgiven for a good one.
Oscar Wilde
Здравствуйте, Didi, Вы писали:
D>Спасибо за подробный ответ. D>И еще вопрос, можно получить тип D>определенного свойства (т.е. строка, объект, целое число и пр.)
Набросал пример использования:
program Test;
{$APPTYPE CONSOLE}uses SysUtils, TypInfo, Classes;
type{$M+} // Для возможности чтения свойств в run-time нужно включить генерацию RTTI для данного класса
TMyClass = class
private
function GetDoubleProperty: Double;
function GetIntegerProperty: Integer;
function GetStringProperty: string;
function GetCharProperty: Char;
published
property StringProperty: string read GetStringProperty;
property IntegerProperty: Integer read GetIntegerProperty;
property DoubleProperty: Double read GetDoubleProperty;
property CharProperty: Char read GetCharProperty;
end;
{$M-}function TMyClass.GetCharProperty: Char;
begin
Result := 'y';
end;
function TMyClass.GetDoubleProperty: Double;
begin
Result := 5.5;
end;
function TMyClass.GetIntegerProperty: Integer;
begin
Result := 7;
end;
function TMyClass.GetStringProperty: string;
begin
Result := 'abcde';
end;
function GetPropValue(Instance: TObject; PropName: string): Variant;
begin
case PropType(Instance.ClassType, PropName) of
tkInteger: Result := GetOrdProp(Instance, PropName);
tkFloat: Result := GetFloatProp(Instance, PropName);
tkLString: Result := GetStrProp(Instance, PropName);
else
Result := 'unsupported property type';
end;
end;
var
Obj: TMyClass;
begin
Obj := TMyClass.Create;
Writeln('StringProperty = ', VarToStr(GetPropValue(Obj, 'StringProperty')));
Writeln('IntegerProperty = ', VarToStr(GetPropValue(Obj, 'IntegerProperty')));
Writeln('DoubleProperty = ', VarToStr(GetPropValue(Obj, 'DoubleProperty')));
Writeln('CharProperty = ', VarToStr(GetPropValue(Obj, 'CharProperty')));
Obj.Free;
Readln;
end.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
It is always bad to give advices, but you will be never forgiven for a good one.
Oscar Wilde
DM>> if not IsPropertyInfo(Obj,PropertyName,PropInfo) then exit;
DM>> Result:=GetStrProp(Obj,PropInfo);
DM>>end;
DM>>
Ты так думаешь? Закоментируй её и запусти:
procedure TForm8.FormCreate(Sender: TObject);
var
S: string;
begin
S := 'Test';
Caption := S;
S := GetStringProperty(Self, 'Абракадабра');
ShowMessage(S);
end;
Компилятор вставляет код инициализации и финализации для длинных строк и интерфейсов в начале и конце каждой процедуры. Строки он инициализирует nil, что эквивалентно пустой строке, поэтому явная инициализация избыточна.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
It is always bad to give advices, but you will be never forgiven for a good one.
Oscar Wilde
MY>Выводит пустую строку, а что?
А у меня выдало Test
MY>Компилятор вставляет код инициализации и финализации для длинных строк и интерфейсов в начале и конце каждой процедуры. Строки он инициализирует nil, что эквивалентно пустой строке, поэтому явная инициализация избыточна.
Инициализация проводится только для локальных/глобальных переменных, но не для Result
ЗЫ Ты точно закоментировал строку Result := '' ??
function GetStringProperty(Obj: TPersistent; PropertyName: string): string;
var PropInfo: PPropInfo;
begin// Result:='';if not IsPropertyInfo(Obj,PropertyName,PropInfo) then exit;
Result:=GetStrProp(Obj,PropInfo);
end;
Здравствуйте, Jack128, Вы писали:
MY>>Выводит пустую строку, а что? J>А у меня выдало Test
Хм, а какая версия Delphi? У меня пятая
J>Инициализация проводится только для локальных/глобальных переменных, но не для Result
Мне казалось что к Result применимы те же правила, что и для локальных переменных. Т.е. это по сути неявная локальная переменная.
J>ЗЫ Ты точно закоментировал строку Result := '' ??
Да.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
It is always bad to give advices, but you will be never forgiven for a good one.
Oscar Wilde
Здравствуйте, Jack128, Вы писали:
J>Здравствуйте, Master Yoda, Вы писали:
MY>>Выводит пустую строку, а что? J>А у меня выдало Test
MY>>Компилятор вставляет код инициализации и финализации для длинных строк и интерфейсов в начале и конце каждой процедуры. Строки он инициализирует nil, что эквивалентно пустой строке, поэтому явная инициализация избыточна. J>Инициализация проводится только для локальных/глобальных переменных, но не для Result
Пардоньте.. С каких пор? Я всегда считал, что
If you don’t explicitly initialize a global variable, the compiler initializes it to 0. Local variables, in contrast, cannot be initialized in their declarations and contain random data until a value is assigned to them.
Здравствуйте, Skyle, Вы писали:
MY>>>Компилятор вставляет код инициализации и финализации для длинных строк и интерфейсов в начале и конце каждой процедуры. Строки он инициализирует nil, что эквивалентно пустой строке, поэтому явная инициализация избыточна. J>>Инициализация проводится только для локальных/глобальных переменных, но не для Result
S>Пардоньте.. С каких пор? Я всегда считал, что
S>If you don’t explicitly initialize a global variable, the compiler initializes it to 0. Local variables, in contrast, cannot be initialized in their declarations and contain random data until a value is assigned to them.
Это справедливо только в отношении "примитивных" типов (целочисленных, вещественных, символьных и т.п.), объектов классов, а также структур и объектов "старого типа" (object), содержащих такие типы. Что же касается длинных строк, динамических массивов и интерфейсов — то они всегда неявно инициализируются в начале каждой процедуры/функции значением nil. Если бы это было не так, компилятор не смог бы обеспечить корректный подсчет ссылок для таких типов.
Т.е. предположим что компилятор не инициализирует такие переменные, а оставляет в них мусор, содержавшийся в этот момент на стеке, тогда:
var
s: string;
begin// здесь s содержит мусор, что-то вроде string($12345)
// ...
// Присваиваем s некоторое значение
s := 'abcde'; // (*)
// ....end;
В строке (*) компилятор должен вставить вызов финализации для переменной s и записи в него нового значения. Прежде всего он проверяет равенство указателя s на nil. Очевидно что в нашем случае это не так. Тогда следующий его шаг — вызов процедуры уменьшения счетчика ссылок для строки s, и, если он достигает нуля, освобождение памяти, занятой под строку. Очевидно что эти операции будут выполняться на невалидном указателе и скорее всего приведут к ошибке доступа к памяти (в лучшем случае).
Из этого очевидно, что все типы Object Pascal aka Delphi, с автоматическим управлением памяти должны всегда инициализироваться неким осмысленным значением в начале каждой процедуры/функции (в качестве значения вполне обоснованно выбран nil). То же самое касается и неявной переменной Result
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
It is always bad to give advices, but you will be never forgiven for a good one.
Oscar Wilde
Здравствуйте, Master Yoda, Вы писали:
MY>Здравствуйте, Skyle, Вы писали:
MY>>>>Компилятор вставляет код инициализации и финализации для длинных строк и интерфейсов в начале и конце каждой процедуры. Строки он инициализирует nil, что эквивалентно пустой строке, поэтому явная инициализация избыточна. J>>>Инициализация проводится только для локальных/глобальных переменных, но не для Result
S>>Пардоньте.. С каких пор? Я всегда считал, что
S>>If you don’t explicitly initialize a global variable, the compiler initializes it to 0. Local variables, in contrast, cannot be initialized in their declarations and contain random data until a value is assigned to them.
MY>Это справедливо только в отношении "примитивных" типов (целочисленных, вещественных, символьных и т.п.), объектов классов, а также структур и объектов "старого типа" (object), содержащих такие типы. Что же касается длинных строк, динамических массивов и интерфейсов — то они всегда неявно инициализируются в начале каждой процедуры/функции значением nil. Если бы это было не так, компилятор не смог бы обеспечить корректный подсчет ссылок для таких типов.
Мда.. Прошу прощения. За тредом не следил и не обратил внимания, что речь о строках.
Тогда да, полностью согласен.
В самую точку!!! Delphi подсовывает при вызове функции адрес на переменную в которую необходимо записать значение. Фактически при изменеии Result мы меняем локальную переменную s.
Тоесть вариант вызова для:
function GetString: string;
begin
ShowMessage (Result); // 'Master Yoda'end;
procedure TestProc;
var
s: string;
begin
s := 'Master Yoda';
s := GetString;
ShowMessage(s); // s is equal to 'Master Yoda'; s is not emptyend;
будеть выглядеть так:
s := GetString;lea eax,[ebp-$08] // просто запихиваем локалный "s"
call GetString
А для варианта с глобальной переменной:
var
s: string;
function GetString: string;
begin
ShowMessage (Result); // ''end;
procedure TestProc;
begin
s := 'Master Yoda';
s := GetString;
ShowMessage(s); // s is emptyend;
s := GetString;lea eax,[ebp-$0c] // подсовываем невидимую локальную переменную (она ессесна пустая)
call GetString
mov edx,[ebp-$0c]
mov eax,$00465c08
call @LStrAsg // копируем из локальной в глобальную переменную "s"
To Master Yoda: учтите это. Можна таких багов нахватать...
Здравствуйте, Master Yoda, Вы писали:
MY>Здравствуйте, Jack128, Вы писали:
MY>Мне казалось что к Result применимы те же правила, что и для локальных переменных. Т.е. это по сути неявная локальная переменная.
Это не так. Если результат присваивается в переменную, то Result — это неявный var параметр.
Т.е.
function Foo(i: Integer): Boolean;
эквивалентно
procedure Foo(var Result: Boolean; i: Integer);
Можно даже так написать:
function GetStr: string;
begin
if Result = 'OK'then Result := 'Not OK';
end;
var
s: string;
begin
s := 'OK';
s := GetStr; // будет 'Not OK'end;