3

我需要帮助:

我将对象属性存储在 DataPacket 类中。属性是这样定义的

type
  TProperty = class
  private
    FName: string;
  public
    constructor Create(const AName: string);
    property Name: string read FName;
  end;

  TIntegerProperty = class(TProperty)
  private
    FValue: Integer;
  protected
    procedure SetValue(const AValue:integer);
  public
    property Value: Integer read FValue write SetValue;
  end;

数据包类:

type
  TDataPacket = class
  private
    FProperties: TStringList;
  public
    function GetIntegerValue(const APropertyName: string): integer;
    .....
    procedure SetIntegerValue(const APropertyName: string; AValue: integer);
end;

它们的实现方式如下:

function TDataPacket.GetIntegerValue(const APropertyName: string): integer;
var
  Pos: integer;
begin
  Pos := FProperties.IndexOf(APropertyName);
  if Pos > -1 then
    Result := TIntegerProperty(FProperties.Objects[Pos]).Value
  else
    Result := 0;
end;

procedure TDataPacket.SetIntegerValue(const APropertyName: string; AValue: integer);
var
  Pos: integer;
  AProperty: TIntegerProperty;
begin
  Pos := FProperties.IndexOf(APropertyName);
  if Pos >- 1 then
    TIntegerProperty(FProperties.Objects[Pos]).Value := AValue
  else
    begin
      AProperty:= TIntegerProperty.Create(APropertyName);
      AProperty.Value := AValue;
      FProperties.AddObject(APropertyName, AProperty);
    end;
end;

现在的问题是:我需要定义一个定义为 TObjectStatus 的 Status 属性,其中:

type
  TStatus = (Deleted, Unchanged, Added , Modified, ChildsModified);

  TObjectStatus = Set of TStatus;

关于如何定义、存储和检索它的任何想法?

抱歉冗长的解释,并提前感谢您的帮助

迈克尔

4

2 回答 2

1

First:

Result := TIntegerProperty(FProperties.Objects[Pos]).Value

Is risky because you will crash if it is not a TIntegerProperty. Use something like:

Pos := FProperties.IndexOf(APropertyName);
if (Pos >= 0) and (FProperties.Objects[Pos] is TIntegerProperty) then
  Result := TIntegerProperty(FProperties.Objects[Pos]).Value
else
  Result := 0;

Next the status, I don't think you need them al:

For the list - Deleted a child: Deleted - Added a child: Added - Child had been changed: ChildsModified

You don't need unchanged because in that case, the set is empty. And you don't need Modified because in that case the set is not empty.

For the properties you can just add a Changed value. You can add ChildsModified directly if a child is changed. Or you can use lazy evaluation and walk all children to check for Changed.

Ok you can do something like this:

type
  TStatus = (stDeleted, stAdded , stModified, stChildsModified);
  TObjectStatus = Set of TStatus;


  TDataPacket = class;
  TProperty = class
  private
    FName   : string;
    FParent : TDataPacket; 
  protected
    procedure NotifyChange(const AStatus: TStatus);
  public
    constructor Create(const AParent: TDataPacket; const AName: string);
    property Name: string read FName;
  end;

  TIntegerProperty = class(TProperty)
  private
    FValue: Integer;
    procedure SetValue(const AValue:integer);
  public
    property Value: Integer read FValue write SetValue;
  end;

  TDataPacket = class
  private
    FProperties: TStringList;
    FStatus : TObjectStatus;
  protected 
    procedure NotifyChange(const AStatus: TStatus);

    function GetProperty(const AName: string): TProperty;
  public
    function GetIntegerValue(const APropertyName: string): integer;
    procedure SetIntegerValue(const APropertyName: string; AValue: integer);
  end;


procedure TProperty.NotifyChange(const AStatus: TStatus);
begin
  FParent.NotifyChange(AStatus);
end;

constructor TProperty.Create(const AParent: TDataPacket; const AName: string);
begin
  Assert(AParent<>nil);
  FName := AName;
  FParent := AParent;
end;

procedure TIntegerProperty.SetValue(const AValue:integer);
begin
  if AValue<>FValue then begin
    FValue := AValue;
    NotifyChange(stChildsModified);
  end;
end;

procedure TDataPacket.NotifyChange(const AStatus: TStatus);
begin
  if AProp=nil then begin
    case AStatus of

  TStatus = (stDeleted, stAdded , stModified, stChildsModified);

  FStatus := FStatus + [AStatus];
end;

function TDataPacket.GetProperty(const AName: string): TProperty;
var
  i : Integer;
begin
  i := FProperties.IndexOf(AName);
  if i>=0 then
    Result := TProperty(FProperties.Objects[i])
  else
    Result := nil;
end;

function TDataPacket.GetIntegerValue(const APropertyName: string): integer;
var
  prop : TProperty;
begin
  prop := GetProperty(APropertyName);
  if (prop<>nil) and (prop is TIntegerProperty) then
    Result := TIntegerProperty(prop).Value
  else
    Result := 0; 
end;

procedure TDataPacket.SetIntegerValue(const APropertyName: string; AValue: integer);
var
  prop : TProperty;
  intprop : TIntegerProperty; 
begin
  prop := GetProperty(APropertyName);
  if (prop<>nil) and not (AProperty is TIntegerProperty) then begin
    // PANIC!
  end else begin
    if prop=nil then begin
      intprop := TIntegerProperty.Create(self, APropertyName);
      intprop.Value := AValue;
      FProperties.AddObject(APropertyName, intprop);
      NotifyChange(stAdded);
    end else begin
      TIntegerProperty(prop).Value := AValue;   
    end;
  end;
end;

And off course add support for deletion.

You can let the Property handle all changes (Add when constructed and Delete when freed).

于 2009-03-20T20:52:56.270 回答
1

如果您正在存储一个对象的属性,并且其中一个属性应该是状态属性,那么您最终需要做的就是与您为 所做的相同TIntegerProperty,但IntegerTObjectStatus.

TObjectStatus首先,定义另一个保存您的值的属性类:

type
  TObjectStatusProperty = class(TProperty)
  private
    FValue: TObjectStatus;
  protected
    procedure SetValue(const AValue: TObjectStatus);
  public
    property Value: TObjectStatus read FValue write SetValue;
  end;

接下来,将方法添加到您的数据包以使用该类型的属性:

function TDataPacket.GetObjectStatusValue(
  const APropertyName: string): TObjectStatus;
var
  Pos: integer;
  Prop: TProperty;
begin
  Pos := FProperties.IndexOf(APropertyName);
  if Pos >= 0 then begin
    Prop := FProperties.Objects[Pos] as TProperty;
    Assert(Prop.Name = APropertyName);
    if Prop is TObjectStatusProperty then
      Result := TObjectStatusProperty(Prop).Value
    else
      raise EWrongPropertyType.CreateFmt('Expected %s but got %s',
        [TObjectStatusProperty.ClassName, Prop.ClassName]);
  end else
    Result := [];
end;

procedure TDataPacket.SetObjectStatusValue(
  const APropertyName: string; AValue: TObjectStatus);
var
  Pos: integer;
  Prop: TProperty;
begin
  Pos := FProperties.IndexOf(APropertyName);
  if Pos >= 0 then begin
    Prop := FProperties.Objects[Pos] as TProperty;
    Assert(Prop.Name = APropertyName);
    if Prop is TObjectStatusProperty then
      TObjectStatusProperty(Prop).Value := AValue
    else
      raise EWrongPropertyType.CreateFmt('Expected %s but got %s',
        [TObjectStatusProperty.ClassName, Prop.ClassName]);
  end else begin
    Prop := TObjectStatusProperty.Create(APropertyName);
    TObjectStatusProperty(Prop).Value := AValue;
    FProperties.AddObject(APropertyName, Prop);
  end;
end;

如果您拥有 Delphi 2009 并且 Delphi 的泛型支持集合,这可能是使用泛型减少您需要编写的类数量的绝佳机会。TXProperty

于 2009-03-21T15:42:59.330 回答