How to Set a Value to a Sub-Property Item using TypInfo RTTI Methods?
Asked Answered
M

1

3

In my Question: How to use “Sender” parameter with “As” operator for more then one class at a time

I choose the Remy Lebeau's Answer because it was the most dynamic tech for most situations like that. It uses the RTTI TypInfo Class.

But as I was using this class, another problem came: How do we Set a sub-property value?

function TRemote.UpdateQuery(DataSet: TDataSet; SQL: String): Boolean;
var
  PropInfo: PPropInfo;
begin
{ atualiza o código SQL padrão de um dataSet de consulta tipo View }
  PropInfo := GetPropInfo(DataSet, 'SQL', []);
  if not Assigned(PropInfo) then
  begin
    Result := False;
    Exit;
  end;
  try
    DataSet.Close;
    SetPropValue(DataSet, PropInfo, SQL);
    DataSet.Open;
    Result := True;
  except
    Result := False;
  end;
end;

Example: I have a TIBQuery and I want to update the text of the SQL property. But the SQL property is a TStrings class, so I have to use SQL.Text. In the code above, It will raise an error "Invalid Property Type" because I got a TStrings and later I try to Set a normal String.

How to reach the SQL.Text using GetPropInfo? Is there a common ancestor of TIBQuery and TZQuery that has the SQL property, so I can change to, instead of the TDataSet in the function parameter?

Mandate answered 30/7, 2012 at 19:14 Comment(5)
Can't you just create a local string list, SQLstrings := TStringList.Create, then do SQLstrings.Text := SQL, and finally pass SQLstrings to SetPropValue?Mortician
The SQL instance you can get simply with TStrings(GetObjectProp(DataSet, 'SQL')). Are you sure you need to use the GetPropInfo ? It will be unreadable piece of code.Struthious
Requesting a property by String instead of by PPropInfo will raise an exception if the property cannot be found.Adamok
@DavidHeffernan I've tried, but the compiler says that we can't use TStrings with SetPropValue.Mandate
You need to use SetObjectProp() instead. SetPropValue() does not supports objects.Adamok
A
9

The TStrings.Text property is not accessible via RTTI in Delphi 2006. Even if it were, you do not need to use RTTI to access it anyway. Since you know the SQL property is a TStrings object, you can simply retreive the actual object pointer from the property and type-cast it to a TStrings pointer, then you can do whatever you need to do with that object, eg:

function TRemote.UpdateQuery(DataSet: TDataSet; SQL: String): Boolean; 
var 
  PropInfo: PPropInfo; 
  SQLObj: TStrings;
begin 
  Result := False; 
  try 
    PropInfo := GetPropInfo(DataSet, 'SQL', [tkClass]); 
    if not Assigned(PropInfo) then Exit; 
    SQLObj := TStrings(GetObjectProp(DataSet, PropInfo, TStrings));
    if not Assigned(SQLObj) then Exit; 
    DataSet.Close; 
    SQLObj.Text := SQL; 
    DataSet.Open; 
    Result := True; 
  except 
  end; 
end; 
Adamok answered 30/7, 2012 at 19:39 Comment(4)
+1; @EASI, I know you've asked this specifically, but you can use directly GetObjectProp. There's no advantage of using GetPropInfo before (it is called inside of the other GetObjectProp overload).Struthious
Calling GetPropInfo() before GetObjectProp() allows you to avoid an exception being raised if the property is not found. The other overloaded version of GetObjectProp() does not give you that option, it will raise an exception. Which I guess is OK in this case due to the try/except, but in general, if you can avoid an exception, you avoid the overhead that goes with it.Adamok
This is great. I've completely forgot to see GetObjectProp. This is very educative!Mandate
I did not found the common Ancestor for TIBQuery and TZQuery (from ZeosLib) but I remembered to use the Params property. So I don't need to use SQL property at all. I just need to set the :Parameters in the correct place and them alter it's contents by DS.ParamByName('ActivityType').AsString := ...Mandate

© 2022 - 2024 — McMap. All rights reserved.