在Nullable< T>中设置值.用RTTI记录

编程入门 行业动态 更新时间:2024-10-24 10:14:49
本文介绍了在Nullable< T>中设置值.用RTTI记录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我正在使用Paolo Rossi的 NEON 库进行序列化/反序列化.

I'm working with Serialization/Deserialization using NEON library from Paolo Rossi.

我正在尝试使用RTTI以及从数据库中获取的数据来填充此类.该类上的属性与数据库中的字段具有相同的名称.

i'm trying to populate this class using RTTI, with data that i get from a database. The properties on the class have the same name of the fields in the database.

在图书馆里,我有这个可空记录:

In the library, i have this Nullable Record :

unit Neon.Core.Nullables; interface uses System.SysUtils, System.Variants, System.Classes, System.Generics.Defaults, System.Rtti, System.TypInfo, System.JSON; type ENullableException = class(Exception); {$RTTI EXPLICIT FIELDS([vcPrivate]) METHODS([vcPrivate])} Nullable<T> = record private FValue: T; FHasValue: string; procedure Clear; function GetValueType: PTypeInfo; function GetValue: T; procedure SetValue(const AValue: T); function GetHasValue: Boolean; public constructor Create(const Value: T); overload; constructor Create(const Value: Variant); overload; function Equals(const Value: Nullable<T>): Boolean; function GetValueOrDefault: T; overload; function GetValueOrDefault(const Default: T): T; overload; property HasValue: Boolean read GetHasValue; function IsNull: Boolean; property Value: T read GetValue; class operator Implicit(const Value: Nullable<T>): T; class operator Implicit(const Value: Nullable<T>): Variant; class operator Implicit(const Value: Pointer): Nullable<T>; class operator Implicit(const Value: T): Nullable<T>; class operator Implicit(const Value: Variant): Nullable<T>; class operator Equal(const Left, Right: Nullable<T>): Boolean; class operator NotEqual(const Left, Right: Nullable<T>): Boolean; end; NullString = Nullable<string>; NullBoolean = Nullable<Boolean>; NullInteger = Nullable<Integer>; NullInt64 = Nullable<Int64>; NullDouble = Nullable<Double>; NullDateTime = Nullable<TDateTime>; implementation uses Neon.Core.Utils; { Nullable<T> } constructor Nullable<T>.Create(const Value: T); var a: TValue; begin FValue := Value; FHasValue := DefaultTrueBoolStr; end; constructor Nullable<T>.Create(const Value: Variant); begin if not VarIsNull(Value) and not VarIsEmpty(Value) then Create(TValue.FromVariant(Value).AsType<T>) else Clear; end; procedure Nullable<T>.Clear; begin FValue := Default(T); FHasValue := ''; end; function Nullable<T>.Equals(const Value: Nullable<T>): Boolean; begin if HasValue and Value.HasValue then Result := TEqualityComparer<T>.Default.Equals(Self.Value, Value.Value) else Result := HasValue = Value.HasValue; end; function Nullable<T>.GetHasValue: Boolean; begin Result := FHasValue <> ''; end; function Nullable<T>.GetValueType: PTypeInfo; begin Result := TypeInfo(T); end; function Nullable<T>.GetValue: T; begin if not HasValue then raise ENullableException.Create('Nullable type has no value'); Result := FValue; end; function Nullable<T>.GetValueOrDefault(const Default: T): T; begin if HasValue then Result := FValue else Result := Default; end; function Nullable<T>.GetValueOrDefault: T; begin Result := GetValueOrDefault(Default(T)); end; class operator Nullable<T>.Implicit(const Value: Nullable<T>): T; begin Result := Value.Value; end; class operator Nullable<T>.Implicit(const Value: Nullable<T>): Variant; begin if Value.HasValue then Result := TValue.From<T>(Value.Value).AsVariant else Result := Null; end; class operator Nullable<T>.Implicit(const Value: Pointer): Nullable<T>; begin if Value = nil then Result.Clear else Result := Nullable<T>.Create(T(Value^)); end; class operator Nullable<T>.Implicit(const Value: T): Nullable<T>; begin Result := Nullable<T>.Create(Value); end; class operator Nullable<T>.Implicit(const Value: Variant): Nullable<T>; begin Result := Nullable<T>.Create(Value); end; function Nullable<T>.IsNull: Boolean; begin Result := FHasValue = ''; end; class operator Nullable<T>.Equal(const Left, Right: Nullable<T>): Boolean; begin Result := Left.Equals(Right); end; class operator Nullable<T>.NotEqual(const Left, Right: Nullable<T>): Boolean; begin Result := not Left.Equals(Right); end; procedure Nullable<T>.SetValue(const AValue: T); begin FValue := AValue; FHasValue := DefaultTrueBoolStr; end; end.

这是模型类:

type TMyClass = class(TPersistent) private FMyIntegerProp: Nullable<Integer>; procedure SetMyIntegerProp(const Value: Nullable<Integer>); published Property MyIntegerProp: Nullable<Integer> read FMyIntegerProp write SetMyIntegerProp; end; implementation { TMyClass } procedure TMyClass.SetMyIntegerProp(const Value: Nullable<Integer>); begin FMyIntegerProp := Value; end;

到目前为止,我的代码是

And my code so far :

procedure DatasetToObject(AObject: TObject; AQuery: TFDQuery); var n: Integer; LRttiContext: TRttiContext; LRttiType: TRttiType; LRttiProperty: TRttiProperty; LFieldName: string; Value: TValue; LValue: TValue; LRttiMethod : TRttiMethod; begin LRttiContext := TRttiContext.Create; try LRttiType := LRttiContext.GetType(AObject.ClassType); for n := 0 to AQuery.FieldCount - 1 do begin LRttiProperty := LRttiType.GetProperty(AQuery.Fields[n].FieldName); if (LRttiProperty <> nil) and (LRttiProperty.PropertyType.TypeKind = tkRecord) then begin LValue := LRttiProperty.GetValue(AObject); LRttiMethod := LRttiContext.GetType(LValue.TypeInfo).GetMethod('SetValue'); if (LRttiProperty.PropertyType.Name = 'Nullable<System.Integer>') then LRttiMethod.Invoke(LValue, [AQuery.Fields[n].AsInteger]).AsInteger; end; end; finally LRttiContext.Free; end; end;

但到目前为止没有成功,将不胜感激.

but no success so far, any help will be appreciated.

推荐答案

Nullable.SetValue()没有返回值,但是您尝试在调用 AsInteger时读取一个值在 TRttiMethod.Invoke()返回的 TValue 上.这将导致在运行时引发异常.

Nullable.SetValue() does not have a return value, but you are trying to read one when you call AsInteger on the TValue that TRttiMethod.Invoke() returns. That will cause an exception to be raised at runtime.

此外,当您读取 TMyClass.MyIntegerProp 属性的值时,最终将得到其 Nullable 记录的 copy ,因此该副本上的 Invoke()'ing SetValue()不会更新 MyIntegerProp 属性.之后,您必须将修改后的 Nullable 分配回 MyIntegerProp ,例如:

Also, when you read the value of the TMyClass.MyIntegerProp property, you will end up with a copy of its Nullable record, so Invoke()'ing SetValue() on that copy is not going to update the MyIntegerProp property. You will have to assign the modified Nullable back to MyIntegerProp afterwards, eg:

LValue := LRttiProperty.GetValue(AObject); LRttiMethod := LRttiContext.GetType(LValue.TypeInfo).GetMethod('SetValue'); LRttiMethod.Invoke(LValue, [AQuery.Fields[n].AsInteger]); LRttiProperty.SetValue(AObject, LValue); // <-- add this!

话虽这么说, Nullable.Value 属性是只读的,但是 Nullable 有一个 SetValue()方法,所以我会建议将 Value 属性更改为可读写,例如:

That being said, the Nullable.Value property is read-only, but Nullable has a SetValue() method, so I would suggest changing the Value property to be read-write instead, eg:

property Value: T read GetValue write SetValue;

然后,您可以通过RTTI设置 Value 属性,而不用直接通过 SetValue()方法设置 Invoke():

Then you can set the Value property via RTTI instead of Invoke()'ing the SetValue() method directly:

var ... //LRttiMethod: TRttiMethod; LRttiValueProp: TRttiProperty; ... ... LRttiProperty := LRttiType.GetProperty(AQuery.Fields[n].FieldName); if (LRttiProperty <> nil) and (LRttiProperty.PropertyType.TypeKind = tkRecord) and (LRttiProperty.PropertyType.Name = 'Nullable<System.Integer>') then begin LValue := LRttiProperty.GetValue(AObject); { LRttiMethod := LRttiContext.GetType(LValue.TypeInfo).GetMethod('SetValue'); LRttiMethod.Invoke(LValue, [AQuery.Fields[n].AsInteger]); } LRttiValueProp := LRttiContext.GetType(LValue.TypeInfo).GetProperty('Value'); LRttiValueProp.SetValue(LValue.GetReferenceToRawData, AQuery.Fields[n].AsInteger); LRttiProperty.SetValue(AObject, LValue); end;

更多推荐

在Nullable&lt; T&gt;中设置值.用RTTI记录

本文发布于:2023-11-11 06:56:39,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1577695.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:amp   Nullable   lt   RTTI   gt

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!