type
  TRec=record
    a:Integer;
    b:Integer;
  end;  TA=class(TObject)
  private
    FABC:TRec;
  public
    constructor Create;
    ......
    property ABC:TRec read FABC;
  end;constructor TA.Create;
begin// 下面语句编译不能通过
  ABC.a:=10;  // Left side cannot be assigned to 
  ABC.b:=10;  // Left side cannot be assigned to // 但你只要这样写,却可以顺利通过编译
// 这可能影响到我们的类的健壮性。
  with ABC do
  begin
    a:=10;
    b:=10;
  end;
end;

解决方案 »

  1.   

    嗬嗬,真的,用变量也不行。不知道为什么with可以。这个怎么回事呢?不好解释…… 唉……最好还是弄个GetXXX的函数吧。
      

  2.   

    怀疑:
    property ABC:TRec read FABC;应该是:
    property ABC:TRec read FABC write FABC;吧?没有write怎么赋值啊!
      

  3.   

    搂主,误会你的意思了。
    不过,你如何想到用with的?佩服!
      

  4.   

    这样也是可以的:
    constructor TA.Create;
    var
      X:TRec;
    begin
      X:=ABC;
      X.a:=10;
      X.b:=10;
      

  5.   

    to tonylk(=www.tonixsoft.com=) 你还不明白吗?就是可以通过属性,往私有成员里面写入数据。你的那个当然不是Bug,关键是私有成员。private
      FABC: TRec;这个。
      

  6.   

    通过这个问题我想到了我夜出现过这个问题。。
    就是TLISTVIEW地问题。。
    增加数据地时候,如果直接是add地花好像不能很好地控制数据
    如下;  listitems:=lv1.Items.Add;
      with listitems do
      begin
        caption:=aq1.Fields[2].Value;
        SubItems.Add(aq1.Fields[0].value);
      end;
    aq1.Next;
    我也不知道什么原因。我想应该是with地用法了。。
    关注中
      

  7.   

    我猜测可能是这样的,假设你的TRec不是Record而是一个对象的话,那么直接写
    ABC.a:=10; 是毫无问题的。因为虽然属性中定义ABC是只读的,只是表明ABC的值——对于对象而言就是指向对象实例的一个引用——是不可更改的。所以下面的代码:
    ABC.a := 10;  //正确,注意ABC的值(对象的地址)没有改变,只是改变了对象实例中的值;
    ABC := TRec.Create;  //错误,不能改变这个引用指向的地址;现在回头再看使用Record的情况,直接写:
    ABC.a := 10; //ABC.a编译器认为是向一个无法更改的变量中赋值,所以出错
    with ABC do
      a := 10;  //这时候的a是指ABC所在内存中a这个位置的值,是一个可以更改的数值,所以没有出错,很类似对象的处理方式所以我认为这是Delphi在实现中的一个不一致的情况,亏楼主这么细心发现了。不过要说对封装性的影响,我觉得是根本就不应该声明结构类型的只读属性。如果Delphi定义为直接赋值是可行的我认为也没什么错。
    再看数组的情况,声明为
    TIntArray = array[0..10] of Integer;
    property Something TIntArray read FSomething;
    那么其实是不能控制数组中的值为只读的,所以Delphi提供了这样定义的方式
    property Something[Index: Integer] read GetSomething;
    这样对这个列中的每个值的读写都是通过类的方法来处理的,而不是通过数据结构。
    同样的道理,上面如果要实现封装,应该分别声明a, b在类中,或者暴露出一个具有只读属性a,b的类来控制a,b的读写(不过Delphi没有友元,直接向Unit中的其他对象的私有数据赋值觉得很不爽)
      

  8.   

    FS: 就是只读属性啊,但用了 with 却可以赋值了
      

  9.   

    asj:
      你的说法有点道理,如果编译器不能识别,只能通过我们程序员来控制了,也就是不提供这种形式的只读属性了。
      

  10.   

    属性不是普通的变量~~
    不要当普通的变量来思维~~
    当取属性值的时候就是调用了GetXXX~~
    当写属性值的时候就是调用了SetXXX~~type
      TForm1 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      private
        function GetPoint: TPoint;
        { Private declarations }
      public
        { Public declarations }
        property Point: TPoint read GetPoint;
      end;
    //....
    procedure TForm1.Button1Click(Sender: TObject);
    begin
    //  Point.X := 1; //这是不能通过编译的~~
      with Point do begin //这不也可以,就当成GetPoint
        X := X + 1;
        Y := Y + 1;
      end;
    end;function TForm1.GetPoint: TPoint;
    begin
      Result := Mouse.CursorPos;
    end;
    //................property ABC: TRec read FABC;with ABC do //就相当于with Get(FABC) do ~~
      

  11.   

    伴水老兄:属性的读写不一定通过过程实现的private
      FABC:Integer;
    public
      property ABC:Integer read FABC write FABC;再有,你没有理解我的意思,我认为在我提出的问题中,用了 with 也不应当编译通过,因为这是一个只读的属性
      

  12.   

    with ABC do
    //实际是对FABC开域了(开了FABC内存地址)~~
    //通过这种方法确实能给只读的属性赋值~~//请做如下测试~~
        property Int: Integer read FInt;
      end;
    //..
    procedure TForm1.Button1Click(Sender: TObject);
    var
      I: PInteger;
    begin
      I := Pointer(@Int);
      I^ := 1234;
      Caption := IntToStr(FInt);
    end;
    //同样可以给一个不是结构类型的只读属性赋值~~
    //同样取Int属性的值时,是把FInt的地址给取了过来~~//继续研究下~~
      

  13.   

    确实如此,看来还是要用 GetXXX, SetXXX 来读写属性值比较可靠。
    如果直接通过私有成员,是存在隐患的。用这种方式编的代码是不是会有安全漏洞啊?:)
      

  14.   

    曾经我就发现可以通过地址改变类型常量的值~~
    procedure TForm1.Button1Click(Sender: TObject);
    const
      C: Integer = 123;
    begin
      PInteger(@C)^ := 456;
      Caption := IntToStr(C);
    end;说道安全漏洞:
    估计这也只能在自己写的程序码中实现~~
    破坏的也只是自己的程序……
    修改内存的工具很多~~
    很多的游戏玩家就会~~
    所以写象登陆等软件时~~
    不要把密码暴露在内存里!~~