How to get the published properties of an persistent object

本文介绍如何使用Delphi的TypeInf单元来获取TPersistent对象的所有已发布属性及其类型信息。通过PPropInfo指针和GetPropertyList函数,可以实现对属性名称的枚举,并筛选特定类型的属性。

How to get the published properties of an persistent object

The TypeInfo unit of Delphi declares several types and functions that gives you easy access to the puplished properties of an object and other informations.
You can obtain a list of the published properties of a class and get the name an type of each property.

The TypeInfo funtion returns a pointer to a type information record. The TypInfo unit declares a real type, that is, a pointer to a TTypeInfo record :

 

  PTypeInfo = ^TTypeInfo;
  TTypeInfo = record
    Kind: TTypeKind;
    Name: ShortString;
  end;


The TTypeKind datatype describes the Datatype , returned by the GetTypeData function.

  TTypeKind = (tkUnknown, tkInteger, tkChar, tkEnumeration, tkFloat,
    tkString, tkSet, tkClass, tkMethod, tkWChar, tkLString, tkWString,
    tkVariant, tkArray, tkRecord, tkInterface, tkInt64, tkDynArray);
  TTypeKinds = set of TTypeKind;

 

Well ... for our first step to access the objects published properties we need to use the PPropInfo-pointer.

  PPropInfo = ^TPropInfo;
  TPropInfo = packed record
    PropType: PPTypeInfo;
    GetProc: Pointer;
    SetProc: Pointer;
    StoredProc: Pointer;
    Index: Integer;
    Default: Longint;
    NameIndex: SmallInt;
    Name: ShortString;
  end;


To clarify it, please take a look at this example :

function GetFontSize(Obj:TPersistent):Integer;
{
in this Procedure we want to get the pPropInfo-pointer - pointing
on the Font-Property from an arbitrary TPersistent-Class.
The return-value in this instance will be the font-size ( if the font
property exists , if not -> the return value will be -1 )
}
var PropInfo:PPropInfo;
begin
  RESULT:=-1;
  // Get the PPropInfo-Pointer for Font of the TPersistent obj
  PropInfo:=GetPropInfo(Obj,'Font');
  // At first we will find out if the property FONT exists
  if PropInfo=nil then
    EXIT; // The Property doesn't exists
  {
    TFont is not an ordinal-Type - therefore will have to control if
    Typekind of the TypeInfo-Class is set to tkClass
  }
  if PropInfo.PropType^.Kind <>tkClass then
    EXIT; // property isn't a tkClass type
  {
    now, we now that the TypeKind of die PropInfo-pointer is a class .
    last but not least we will use the GetObjectProp, the return-value
    of this function is a TObject. Subsequently, we will use this object as
    a TFont to get the Size value.
  }
  RESULT:=( (GetObjectProp(Obj,PropInfo)) as TFont).Size;
end;

 


But to get the complete list of all properties of a TPersistent-Class we will need the pPropList-Type . This type is a simple pointer-array and the magic key to all Property-Informations and their structures.

Take a look at this :

 

procedure TForm1.Button1Click(Sender: TObject);

const tkOrdinal = [tkEnumeration,tkInteger,tkChar,tkSet,tkWChar]; //Filter

begin
{
  in this method of the mainform-class we are seeking for all ordinal-type
  properties of the edit1-component. The from the GetPropertyList method
  returned list of all properties will be written into the Listbox1. You can
  replace the obj parameter with an arbitrary TObject ( but usually TPersistent
  objects ).
  For another filter please take a look at the TTypeKinds-set.
}
  GetPropertyList(Edit1,ListBox1.Items,tkOrdinal);
end;

 

procedure GetPropertyList(Obj:TObject ;List: TStrings;Filter: TTypeKinds);
var PropList:pPropList;
    count,i : Integer;
begin
  List.Clear;
  // Here we'll get the count of the given properties, ...
  Count := GetPropList(Obj.ClassInfo, Filter, nil);
  // ...and create room for the PropList,...
  GetMem(PropList,Count * SizeOf(PPropInfo));
  // ...get the Proplist-Data,...
  GetPropList(Obj.ClassInfo, Filter, PropList);
  // ...and write the property-names into the StringList
  for i:=0 to Count -1 do
    List.Add(Proplist[i].Name);
end;

 

That's it ---- actually easy , or?


best regards

Boris Benjamin Wittfoth

### 解决 Unity 开发中遇到的 `System.InvalidOperationException` 异常问题 在 Unity 开发过程中,`System.InvalidOperationException` 通常表示尝试执行的操作与对象当前状态不兼容。以下是对该问题的详细分析和解决方案。 #### 1. 原因分析 `System.InvalidOperationException: Operation is not valid due to the current state of the object` 的常见原因包括: - 尝试释放未正确分配的资源。例如,在使用 `NativeArray` 或其他原生内存结构时,如果资源未通过有效的分配器创建,则调用 `Dispose` 方法会导致异常[^2]。 - 脚本逻辑中存在状态冲突。例如,脚本尝试在对象未初始化或已销毁的情况下访问其成员。 - 使用 Unity 的 Job System 或 Burst 编译器时,违反了线程安全规则。例如,未正确设置 `AtomicSafetyHandle` 或尝试访问已被标记为无效的对象[^1]。 #### 2. 解决方案 ##### (1) 检查资源分配与释放逻辑 确保所有需要显式释放的资源(如 `NativeArray`、`BlobAssetReference` 等)均通过有效的分配器创建,并且释放操作仅在资源有效时执行。以下是正确的 `NativeArray` 使用示例: ```csharp using Unity.Collections; using UnityEngine; public class NativeArrayExample : MonoBehaviour { private NativeArray<int> array; void Start() { if (!array.IsCreated) { array = new NativeArray<int>(10, Allocator.Persistent); } } void OnDestroy() { if (array.IsCreated) { array.Dispose(); // 正确释放资源 } } } ``` 在上述代码中,`IsCreated` 属性用于检查资源是否已正确分配,从而避免非法释放操作[^2]。 ##### (2) 验证对象状态 确保在访问对象之前验证其状态。例如,检查游戏对象是否已销毁,或组件是否已附加到有效对象上。以下是示例代码: ```csharp using UnityEngine; public class ObjectStateCheck : MonoBehaviour { private GameObject targetObject; void Update() { if (targetObject != null && targetObject.activeInHierarchy) { // 执行操作 } else { Debug.LogWarning("目标对象无效或已销毁"); } } } ``` ##### (3) 处理线程安全问题 在使用 Unity 的 Job System 时,确保遵循线程安全规则。例如,正确管理 `AtomicSafetyHandle` 和 `Dependency`,以避免并发访问冲突。以下是示例代码: ```csharp using Unity.Burst; using Unity.Collections; using Unity.Jobs; using UnityEngine; public class JobSystemExample : MonoBehaviour { private NativeArray<float> data; void Start() { data = new NativeArray<float>(10, Allocator.TempJob); var job = new ProcessDataJob { Data = data }; var handle = job.Schedule(data.Length, 1); handle.Complete(); // 确保主线程等待作业完成 data.Dispose(); } [BurstCompile] public struct ProcessDataJob : IJobParallelFor { public NativeArray<float> Data; public void Execute(int index) { Data[index] = index * 2.0f; } } } ``` 在上述代码中,`handle.Complete()` 确保主线程等待作业完成后继续执行,从而避免线程安全问题。 #### 3. 调试方法 为了更高效地定位问题,可以采用以下调试方法: - 使用 `Debug.Log` 输出关键变量的状态,确保其符合预期。 - 在 Unity 控制台中启用“Pause on Exception”选项,以便在异常发生时立即暂停程序并检查调用栈。 - 检查 Unity 版本是否与使用的 API 兼容,必要时更新 Unity 或调整代码逻辑。 ### 总结 通过验证资源分配与释放逻辑、对象状态以及线程安全规则,可以有效解决 `System.InvalidOperationException` 异常问题。同时,结合调试工具和日志输出,能够更快地定位并修复问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值