什么是RTTI

RTTI(Run-time Type Information)是Delphi编程语言中的一个重要特性,它允许我们在程序运行过程中获取对象的类型信息,包括类型名、属性、字段、方法等。通过RTTI,我们可以在运行时对对象进行动态操作,以及进行一些高级功能,如反射和序列化等。

使用RTTI获取类型信息

要使用RTTI,首先需要了解如何获取对象的类型信息。在Delphi中,可以使用类型信息类 TTypeInfo 来获取类型信息。TTypeInfo 包含了类型的各种信息,如类型名、大小、属性、方法等。

1. 获取类型信息


var
  typeInfo: PTypeInfo;
begin
  // 使用 TypeInfo 函数获取类型信息
  typeInfo := TypeInfo(TMyClass);
  // 在使用类型信息前,需要判断其是否为 nil
  if Assigned(typeInfo) then
  begin
    // 获取类型名
    ShowMessage(typeInfo.Name);
    // 获取类型大小
    ShowMessage(IntToStr(typeInfo.TypeSize));
    // 其他操作...
  end;
end;

2. 获取属性信息


var
  context: TRttiContext;
  rttiType: TRttiType;
  rttiProp: TRttiProperty;
begin
  // 创建 RTTI 上下文对象
  context := TRttiContext.Create;
  try
    // 获取指定类型的 RTTI 信息
    rttiType := context.GetType(TMyClass);
    if Assigned(rttiType) then
    begin
      // 遍历类型的属性信息
      for rttiProp in rttiType.GetProperties do
      begin
        // 获取属性名
        ShowMessage(rttiProp.Name);
        // 获取属性类型
        ShowMessage(rttiProp.PropertyType.Name);
        // 其他操作...
      end;
    end;
  finally
    context.Free;
  end;
end;

使用 RTTI 进行动态操作

除了获取类型信息外,RTTI 还可以进行一些动态操作,如创建对象、调用方法、读写属性值等。

1. 创建对象


var
  context: TRttiContext;
  rttiType: TRttiType;
  obj: TObject;
begin
  // 创建 RTTI 上下文对象
  context := TRttiContext.Create;
  try
    // 获取指定类型的 RTTI 信息
    rttiType := context.GetType(TMyClass);
    if Assigned(rttiType) then
    begin
      // 创建对象
      obj := rttiType.GetMethod('Create').Invoke(rttiType.AsInstance.MetaclassType, []).AsObject;
      // 其他操作...
    end;
  finally
    context.Free;
  end;
end;

2. 调用方法


var
  context: TRttiContext;
  rttiType: TRttiType;
  obj: TObject;
  rttiMethod: TRttiMethod;
begin
  // 创建 RTTI 上下文对象
  context := TRttiContext.Create;
  try
    // 获取指定类型的 RTTI 信息
    rttiType := context.GetType(TMyClass);
    if Assigned(rttiType) then
    begin
      // 创建对象
      obj := rttiType.GetMethod('Create').Invoke(rttiType.AsInstance.MetaclassType, []).AsObject;
      // 调用方法
      rttiMethod := rttiType.GetMethod('MyMethod');
      if Assigned(rttiMethod) then
      begin
        rttiMethod.Invoke(obj, [param1, param2]);
        // 其他操作...
      end;
    end;
  finally
    context.Free;
  end;
end;

3. 读取和写入属性值


var
  context: TRttiContext;
  rttiType: TRttiType;
  obj: TObject;
  rttiProp: TRttiProperty;
begin
  // 创建 RTTI 上下文对象
  context := TRttiContext.Create;
  try
    // 获取指定类型的 RTTI 信息
    rttiType := context.GetType(TMyClass);
    if Assigned(rttiType) then
    begin
      // 创建对象
      obj := rttiType.GetMethod('Create').Invoke(rttiType.AsInstance.MetaclassType, []).AsObject;
      // 读取属性值
      rttiProp := rttiType.GetProperty('MyProperty');
      if Assigned(rttiProp) then
      begin
        value := rttiProp.GetValue(obj).ToString;
        // 其他操作...
      end;
      // 写入属性值
      rttiProp := rttiType.GetProperty('MyProperty');
      if Assigned(rttiProp) then
      begin
        rttiProp.SetValue(obj, 'NewValue');
        // 其他操作...
      end;
    end;
  finally
    context.Free;
  end;
end;

使用 RTTI 进行序列化和反射

RTTI 提供了强大的序列化和反射功能,可以将对象转化为字节数组,以及根据类型信息动态创建和操作对象。

1. 序列化


var
  context: TRttiContext;
  rttiType: TRttiType;
  obj: TObject;
  ms: TMemoryStream;
begin
  // 创建 RTTI 上下文对象
  context := TRttiContext.Create;
  try
    // 获取指定类型的 RTTI 信息
    rttiType := context.GetType(TMyClass);
    if Assigned(rttiType) then
    begin
      // 创建对象
      obj := rttiType.GetMethod('Create').Invoke(rttiType.AsInstance.MetaclassType, []).AsObject;
      // 序列化对象为字节数组
      ms := TMemoryStream.Create;
      try
        TRttiMarshal.SaveObject(obj, ms);
        // 其他操作...
      finally
        ms.Free;
      end;
    end;
  finally
    context.Free;
  end;
end;

2. 反射创建对象和调用方法


var
  context: TRttiContext;
  rttiType: TRttiType;
  obj: TObject;
  rttiMethod: TRttiMethod;
begin
  // 创建 RTTI 上下文对象
  context := TRttiContext.Create;
  try
    // 获取指定类型的 RTTI 信息
    rttiType := context.GetType(TMyClass);
    if Assigned(rttiType) then
    begin
      // 使用默认构造函数反射创建对象
      obj := rttiType.GetMethod('Create').Invoke(rttiType.AsInstance.MetaclassType, []).AsObject;
      // 反射调用方法
      rttiMethod := rttiType.GetMethod('MyMethod');
      if Assigned(rttiMethod) then
      begin
        rttiMethod.Invoke(obj, [param1, param2]);
        // 其他操作...
      end;
    end;
  finally
    context.Free;
  end;
end;