Re: установить свойство
От: DarkMaster Украина http://www.bdslib.at.ua
Дата: 02.08.06 10:55
Оценка: 2 (2)
Здравствуйте, 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;


Для свойств других типов — по аналогии....
WBR, Dmitry Beloshistov AKA [-=BDS=-]
Re[7]: установить свойство
От: Jack128  
Дата: 21.08.06 20:57
Оценка: 14 (1)
Здравствуйте, 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>Да.
Re[3]: установить свойство
От: mr_dino  
Дата: 23.08.06 16:11
Оценка: 8 (1)
Здравствуйте, Master Yoda, Вы писали:

MY>Здравствуйте, DarkMaster, Вы писали:


MY><...>


MY>Сорри за придирку :


DM>>
DM>>function GetStringProperty(Obj: TPersistent; PropertyName: string): string;
DM>>var PropInfo: PPropInfo;
DM>>begin
DM>>  Result:=''; // эта инициализация лишняя
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 empty
end;
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
установить свойство
От: Didi  
Дата: 02.08.06 10:45
Оценка:
Привет всем.
Народ напомните мне как имея имя свойства (строку с именем свойства)
установить или считать его значение.

С уважением Didi
Re: установить свойство
От: Master Yoda Великобритания  
Дата: 02.08.06 10:53
Оценка:
Здравствуйте, 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
Re[2]: установить свойство
От: Master Yoda Великобритания  
Дата: 02.08.06 11:04
Оценка:
Здравствуйте, DarkMaster, Вы писали:

<...>

Сорри за придирку :

DM>
DM>function GetStringProperty(Obj: TPersistent; PropertyName: string): string;
DM>var PropInfo: PPropInfo;
DM>begin
DM>  Result:=''; // эта инициализация лишняя
DM>  if not IsPropertyInfo(Obj,PropertyName,PropInfo) then exit;
DM>  Result:=GetStrProp(Obj,PropInfo);
DM>end;
DM>


Хотя допускаю, что может это такой coding-style маниакальный
... << 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
Re[3]: установить свойство
От: Danchik Украина  
Дата: 02.08.06 11:26
Оценка:
Здравствуйте, Master Yoda, Вы писали:

[Skip]

MY>Хотя допускаю, что может это такой coding-style маниакальный


Я всегда пишу инициализацию, воспитывает, понимаеш, аккуратность.
Re[2]: установить свойство
От: Didi  
Дата: 02.08.06 13:08
Оценка:
Спасибо за подробный ответ.
И еще вопрос, можно получить тип
определенного свойства (т.е. строка, объект, целое число и пр.)

С уважением Didi
Re[3]: установить свойство
От: Master Yoda Великобритания  
Дата: 02.08.06 13:12
Оценка:
Здравствуйте, 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
Re[3]: установить свойство
От: Master Yoda Великобритания  
Дата: 03.08.06 04:29
Оценка:
Здравствуйте, 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
Re[3]: установить свойство
От: Jack128  
Дата: 03.08.06 21:24
Оценка:
Здравствуйте, Master Yoda, Вы писали:

MY>Здравствуйте, DarkMaster, Вы писали:


MY><...>


MY>Сорри за придирку :


DM>>
DM>>function GetStringProperty(Obj: TPersistent; PropertyName: string): string;
DM>>var PropInfo: PPropInfo;
DM>>begin
DM>>  Result:=''; // эта инициализация лишняя
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;
Re[4]: установить свойство
От: Master Yoda Великобритания  
Дата: 04.08.06 03:39
Оценка:
Здравствуйте, Jack128, Вы писали:

J>Ты так думаешь? Закоментируй её и запусти:


J>
J>procedure TForm8.FormCreate(Sender: TObject);
J>var
J>  S: string;
J>begin
J>  S := 'Test';
J>  Caption := S;
J>  S := GetStringProperty(Self, 'Абракадабра');
J>  ShowMessage(S);
J>end;
J>


Выводит пустую строку, а что?

Компилятор вставляет код инициализации и финализации для длинных строк и интерфейсов в начале и конце каждой процедуры. Строки он инициализирует 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
Re[5]: установить свойство
От: Jack128  
Дата: 19.08.06 20:28
Оценка:
Здравствуйте, Master Yoda, Вы писали:


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;
Re[6]: установить свойство
От: Master Yoda Великобритания  
Дата: 20.08.06 04:01
Оценка:
Здравствуйте, 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
Re[6]: установить свойство
От: Skyle Россия  
Дата: 21.08.06 04:21
Оценка:
Здравствуйте, 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.
Re[7]: установить свойство
От: Master Yoda Великобритания  
Дата: 21.08.06 04:45
Оценка:
Здравствуйте, 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
Re[8]: установить свойство
От: Skyle Россия  
Дата: 21.08.06 05:45
Оценка:
Здравствуйте, 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. Если бы это было не так, компилятор не смог бы обеспечить корректный подсчет ссылок для таких типов.


Мда.. Прошу прощения. За тредом не следил и не обратил внимания, что речь о строках.
Тогда да, полностью согласен.
Re[4]: установить свойство
От: Danchik Украина  
Дата: 23.08.06 16:51
Оценка:
Здравствуйте, mr_dino, Вы писали:

[Skip]

В самую точку!!! 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 empty
end;

будеть выглядеть так:
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 empty
end;

s := GetString;

  lea eax,[ebp-$0c] // подсовываем невидимую локальную переменную (она ессесна пустая)
  call GetString
  mov edx,[ebp-$0c]
  mov eax,$00465c08 
  call @LStrAsg     // копируем из локальной в глобальную переменную "s"


To Master Yoda: учтите это. Можна таких багов нахватать...
Re[7]: установить свойство
От: mr_dino  
Дата: 23.08.06 16:59
Оценка:
Здравствуйте, 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;
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.