DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: melqui
今日帖子: 21
在线用户: 12
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 chencong5025 (Nicosoft) ▲▲▲△△ -
普通会员
2022/11/21 15:03:34
标题:
Delphi Tobject Record 存疑 浏览:2208
加入我的收藏
楼主: 案例1:
  Monster=record
    id:Integer;
  end;

procedure TForm1.Button5Click(Sender: TObject);
var
  S:Monster;
  obj:Tobject;
begin
   s.id:=1;
   obj:=Tobject(s);
   Showmessage(Monster(obj).id.tostring);
end;
编译通过。工作正常。一旦
  Monster=record
    id:Integer;
    Name:string;
  end;
增加一个成员 就失败了。

Why?  按理说1个成员也该失败把。错误是 类型转换错误

常识应该是   Record 不可以转 Tobject  。

存疑  求大佬解惑
----------------------------------------------
-
作者:
男 zhyhero (zhyhero) ★☆☆☆☆ -
盒子活跃会员
2022/11/21 15:11:42
1楼: 我的问题是,为什么要转换?
----------------------------------------------
z@S7
作者:
男 sail2000 (小帆工作室) ★☆☆☆☆ -
盒子活跃会员
2022/11/21 19:07:40
2楼: 转来转去是为了什么特殊要求?
----------------------------------------------
delphi 是兴趣,和工作无关,即使它倒闭。又不靠它 delphi 吃饭,怕甚?
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2022/11/21 21:06:42
3楼: RAD HELP:
-- TObject is never directly instantiated. Although it does not use programming language features that prevent instantiation, TObject is an abstract class
-----

It should be noted that "local variables" are given a random value when not initialized. And, the compiler might be using a location in memory to reference this variable.

However, when you add one more "member" to the "record", this memory location may not be available for use, so the compiler responds as "I CANNOT USE IT IN THIS POSITION". 

That is, you cannot "type cast" this value to another type in this memory location.

Remembering that the "TObject" is something like a "does everything (or almost everything)". So it accepts many uses, including this weird conversion you're intending to do: "RECORD" to "TOBJECT"!!!

type
  TMonster = record
    ID: integer;
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
  M  : TMonster;
  Obj: TObject;
begin
  Obj := nil;
  //
  // M.ID := 1;  // random now...
  Obj := TObject(M); 
  //
  ShowMessage(TMonster(Obj).ID.ToString);
end;
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 vmao (毛小毛) ★☆☆☆☆ -
盒子活跃会员
2022/11/21 22:07:31
4楼: 额,会不会是再加一个integer或者char之类的简单类型成员还可以?string这个东东在Delphi里似乎是指针。
----------------------------------------------
-
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2022/11/22 0:10:20
5楼: the problem is not a "type" of member, but the "pointer" where it is in.
the pointer can appoint to "1234", "12345", "123456"...

then, the value is get these "place" on memory!

the "TObject" dont know what is this!!! because of your natural usage: generic and abstract source for all!!!!

TObject dont have member like: "ID", or any other member like above!
then, in runtime will be appointed to any "place on memory" -> pointer -> randomic value... 
then, if the value is a "integer" type, normally, but dont sure this, the value will be accepted! because a pointer receive a integer value! but not "a string value, or others..."
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2022/11/22 1:03:17
6楼: Delphi 是强类型的语言,不同的类型,你这样做强制类型转换,即便偶然运气好运行结果符合你的想象,那也是偶然运气碰到的,不能保证。

强制类型转换,被转换的必须就是那个类型才可以。

也就是说,语法上,TObjec(ARecord).ID 这种写法根本就是错误的。

另外,这样写的意义何在?你想达到什么目的?
----------------------------------------------
-
作者:
男 chencong5025 (Nicosoft) ▲▲▲△△ -
普通会员
2022/11/22 1:52:25
7楼: @zhyhero
@sail2000

我是想用ListBox  Addobject 用。

版本11.2   string 也可以直接转Tobject不报错。也工作正常。
然后我测试record 发现单个成员(string,int 均可以)也可以成功 工作也正常

然后我再去测试多个成员就失败 才引出这个问题
----------------------------------------------
-
作者:
男 chencong5025 (Nicosoft) ▲▲▲△△ -
普通会员
2022/11/22 1:53:49
8楼: @emailx45

Record with only one member (string is also work ok)

with one member works ok.
----------------------------------------------
-
作者:
男 chencong5025 (Nicosoft) ▲▲▲△△ -
普通会员
2022/11/22 1:54:16
9楼: @pcplayer

和运气没关系啊  我测试过几百次  都工作正常也没有泄露
----------------------------------------------
-
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2022/11/22 2:28:25
10楼: @chencong5025

  ID:integer;  // 4bytes on memory (pointer)
  ID:string;   // 8Bytes on memory (pointer)

this position (used by cast) is like a "variant" var, then, basically, any value is accepted!

after this position, can:
-- not exists!
-- is another type
-- is used for another references

then, the 2nd member (Field) cannot be referenced or used, you see?
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2022/11/22 2:39:12
11楼: procedure TForm1.BtnRecordToObjectClick(Sender: TObject);
var
  M  : TMonster;
  Obj: TObject;
  S  : string;
begin
  Obj := nil;
  //
  M.ID := 123456; // 123456 = word, integer, cardinal, etc....
  //
  Obj := TObject(M);
  //
  // VarAsType(...) result in a "Variant"!!!
  //
  // VarAsType(M, varRecord); // "M" not variant 
  // VarAsType(Obj, varRecord); // "Obj" not variant 
  //
  // S := VarAsType(M.ID, varByte);  // overflow --> 123456 > byte
  // S := VarAsType(M.ID, varSmallint); // overflow --> > smallint
  // S := VarAsType(M.ID, varObject); // AV --> "integer" into "a type" not possible here!!!
  //
  S := VarAsType(M.ID, varString); // OK until 2GB chars
  //
  ShowMessage(TMonster(Obj).ID.ToString + ', S=' + S);
end;
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 zhyhero (zhyhero) ★☆☆☆☆ -
盒子活跃会员
2022/11/22 2:49:39
10楼: 你可以换个思路,把record存在一个TDictionary<integer,record>的字典里长期保持。ListBox中的Object部分把字典中的record.id保存上。
----------------------------------------------
z@S7
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2022/11/22 4:15:13
12楼: other way:

1) create your RECORD type (with your fields necessary, any type)
   type R = record ....

2) do the "pointer reference" for this new type
   Preference = ^R ...

3) create a ARRAY of this "pointer" reference
   var 
      MyArr[0..n ] of Preference ...
   //
   MyArr[ n ] := Preference^.FIELD_NAME_in_RECORD;
   or
   MyArr := MyArr + [ Preference^.FIELD_NAME_in_RECORD, .... ];

4) cast this "pointer reference" as TObject, and add this new object in your "ITEMS.object" (listbox, stringlist, etc...)
    for R in MyArr do
    begin
      Obj := TObject( R )....
      ListBox1.Items.AddObject( Preference.FIELD_NAME_in_RECORD, Obj);
    end;

5) to retrieve the values onClick ListBox
     P := Preference(ListBox1.Items.Objects[ListBox1.ItemIndex])^; 
     showmessage( p.FIELD_NAME_in_RECORD );

then, you can store your "records" as TObject in any "stringlist" (items)
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 bahamut8348 (leonna) ★☆☆☆☆ -
普通会员
2022/11/22 13:43:17
13楼: 楼主似乎对tobject和record有什么误会。
delphi这种强类型语言里,record结构属于值类型,而tobject类属于引用类型。
所谓引用类型你可以看作是一个指向一个复杂结构的入口地址,也就是指针。
而值类型则是相对简单的类型,也就对应的数据本身。
用书来做比喻,前一个就是目录,后一个是实际内容所在页。

所以也就说明了为什么当record里只有一个integer的时候强转是正常的,而再试图添加任何一个新成员就会报错的原因。因为integer的占用空间与pointer是一样的,再增加就超出pointer的范围了。

只不过如果你真有实际需求,那么可以用@record来强转,只不过以我的经验来看,不如用指针更加通用,而且可读性更高。
----------------------------------------------
--
作者:
男 chencong5025 (Nicosoft) ▲▲▲△△ -
普通会员
2022/11/23 19:12:26
14楼: @bahamut8348

成员可以不仅仅是值类型。可以string  也正常。
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2022/11/23 20:25:50
15楼: 如果想 ListBox.AddObject 的方式来保存数据,那你就应该使用 Object 而不是 Record.

本质上,一个 Object 其实就是一个指针。而一个 Record 是一块内存数据。

另外,AObject := TMyObject.Create 以后,这个 AObject 指针指向的对象所属的内存,就一直存在,除非你释放它。因此把它的指针加到 ListBox 里面去是没有问题的。

而 Record 的问题就来了,你声明一个 ARecord: TMyRectod,其实就直接分配了一块内存。但是,一旦代码离开这个声明的函数,这块内存就不存在了。因此,假设你把它加入到 ListBox 里面,也不能包装它就存在。

除非你全局声明,而且声明不止一个。

如果非要全局声明一堆 record 怎么搞?办法也是有的:

MyRecordList: array[0..99] of TMyRecord。这个声明,等于你直接开辟了一大堆内存,这堆内存的大小就是 100 * SizeOf(TMyRecord).

分配好以后,大概可以按照 13 楼的说法,对这块内存的指针进行引用了。

说到底,不管用什么数据类型,最终你都可以通过分配内存获得指针然后对指针进行操作的手法来写程序。但这样写累啊,所以才有 TObject 的 Create 和 Free,这样整个操作简单很多。

结论:还是自己老实定义一个 Class 吧。面向对象还是好玩很多。大不了你在你的对象里面再放你的 Record。这样,这个 Record 的内存管理就是对象负责了,你不用管。创建了对象,这个 record 就有了。

综上,这里涉及的问题实际上是一个数据的内存管理,生命周期的问题。
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2022/11/23 20:33:02
16楼: 按照楼主的代码:
procedure TForm1.Button5Click(Sender: TObject);
var
  S:Monster;
  obj:Tobject;
begin
   s.id:=1;
   obj:=Tobject(s);
   Showmessage(Monster(obj).id.tostring);

   ListBox1.AddObject(Obj);
end;

这里即便是把 obj 加入到 ListBox1 里面去了,但 ListBox1 里面加入的实际上是它的指针。指针指向的内存块是一个 record 的局部变量,离开这个函数,这个内存块就不存在了。到了别的地方,从 ListBox1 里面取出来的指针,指向的那个内存块,是没有意义的。具体实现的时候,也许你还能读到正确的数据,但那也是运气而已。因为操作一个不存在的内存块,很可能来一个 AV 错误。

总之,语法上就不对,这样的代码是没有意义的。
----------------------------------------------
-
作者:
男 1111111113 (1111111113) ▲△△△△ -
普通会员
2022/11/23 21:13:50
17楼: 为什么要和编译器的语法糖过去不呢?
----------------------------------------------
-
作者:
男 unjiang (css) ★☆☆☆☆ -
盒子活跃会员
2022/11/24 10:51:50
18楼: 12楼是正解!ListBox1.AddObject就是添加一个指针,如果是指针宽度(一般是32位)的内容都可以。Tobject(s),相当于取了s的指针。如果s就是一个变量,地址在编译时候已经确定,s的指针总指向这个地址,无法达到存储多个数值的要求,数值是最后存储的那个。s本身必须是指针,AddObject之前先分配内存,这样才可以存储多个数值。建议楼主看看VirtualTreeView的帮助。
----------------------------------------------
是爱好,就别苛求太多!
作者:
男 bahamut8348 (leonna) ★☆☆☆☆ -
普通会员
2022/11/24 21:59:16
19楼: 14楼或许没有看懂我的意思,或者没有理解string,

我的意思是结构类型是值类型,占用空间随着成员变化而变化,而类是引用类型,本身的大小一直都是一个地址。实际上类的实例就是这个类虚拟方法表的入口地址。

而string本身其实就是delphi的特有类型,它的本质还是一个pointer,只不过包含了引用计数、长度等额外信息罢了。

所以,当你一个record里只有一个string成员的时候,强转并不会有问题。但是一旦超过一个pointer的size的时候,再强转就有极大可能出问题,因为指针越界,超过的部分谁都不知道是什么状态。
----------------------------------------------
--
作者:
男 hexi (Hexi) ★☆☆☆☆ -
盒子活跃会员
2022/11/25 22:52:12
20楼: TObject只有占用4个字节(32位系统)

  Monster=record
    id:Integer;
  end;
Monster占用4字节
  Monster2=record
    id:Integer;
    name:String
  end;
Monster2占用8字节。

Monster2与TOBject占用内存大小不一致。
----------------------------------------------
-
作者:
男 hq200306 (200306) ★☆☆☆☆ -
普通会员
2022/11/26 10:14:18
21楼: Tobject,Record在内存上存储结构不同,

语法上就不对,没有讨论的意义。
----------------------------------------------
-
作者:
男 sail2000 (小帆工作室) ★☆☆☆☆ -
盒子活跃会员
2022/11/29 11:55:45
22楼: type
  PMonster = ^Monster;
  Monster = record
    id: Integer;
    Name: string;
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
  S: PMonster;
  obj: TObject;
begin
  New(S);
  S.id := 1;
  S.Name := 'gagfdsafafad';
  obj := TObject(S);
  Showmessage(PMonster(obj).id.tostring);
  Showmessage(PMonster(obj).Name);
  Dispose(S);
end;
----------------------------------------------
delphi 是兴趣,和工作无关,即使它倒闭。又不靠它 delphi 吃饭,怕甚?
作者:
男 chencong5025 (Nicosoft) ▲▲▲△△ -
普通会员
2022/11/29 16:02:35
23楼: @pcplayer  
@bahamut8348

我知道 record和class的区别。
我用record只是发现居然可以成功。
不喜欢用class的原因是 频繁的释放代码 懒得写。

如果我加入几百个object 我得在 最后释放一轮  只是单纯的讨厌写free,,,,
----------------------------------------------
-
作者:
男 virstyle (virstyle) ★☆☆☆☆ -
普通会员
2022/11/29 16:15:54
24楼: 我只知道 record使用之前需要create 包括成员好像
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行78.125毫秒 RSS