这篇文章的内容是介绍GH_Component中另外一对可以被 override 的函数:

  • Read
  • Write

当我们在自己的电池中直接 override 时,Visual Studio会帮我们添加基类实现:

public override bool Read(GH_IReader reader)
{return base.Read(reader);
}public override bool Write(GH_IWriter writer)
{return base.Write(writer);
}

这一对函数是用来进行序列化电池数据的。它们的最主要的应用场景是将某些属于电池的状态数据 存储 在电池所在的 .gh 文件中。

举个例子:Grasshopper中有许多电池是具备多个形态的,比如 Cross Reference 电池,它的不同工作模式可以使得两个列表对象以不同的方式匹配到一起:

那么问题就来了,Grasshopper是如何实现打开一个 .gh 文件时让这个电池还保持它上次在文件关闭时的电池形态呢?进一步的,GH在文件保存时是怎么知道这个电池处于什么状态下呢?

这里就需要使用到这一对函数了。在Grasshopper打开文件时,会调用电池的Read函数,读取 .gh 文件中属于该电池的数据内容;Write函数正好相反,是在每次 .gh 文件保存时,将属于电池的数据写入到 .gh 文件的数据内容存储区。

电池的序列化

所有的电池其本质上都是一个自定义类,其继承自GH_Component。但所有程序都是在内存中运行的,因此,我们在GH画布上创作的电池其本质都是 在内存中 创造/销毁数据。当我们的自定义电池被拖入GH画布上时,一个自定义电池类的实例就会在内存中被创建;我们在GH画布上删除一个电池时,一个自定义电池类的实例就会在内存中被销毁。

.gh 文件被保存时,这些内存中的电池实例就会被“序列化”至硬盘上。 .gh 文件被打开的时候,Grasshopper就会“反序列化”将硬盘上的内容读取到内存中。

但是,我们都知道,硬盘上只能存储0和1。那一堆0和1是怎么变成我们的自定义类的,我们自定义类又是如何变成0和1?这就需要我们定义“序列化规则”。

自定义电池类的基类GH_Component已经由GH的开发者实现了一套默认的序列化规则,放在这一对函数ReadWrite中来帮助我们实现电池的序列化和反序列化,因此电池中的基础数据就可以被正确地存盘和读取,包括并不限于:

  • 电池的名字(Name)
  • 电池的描述(Description)
  • 电池是否打开预览(Preview)
  • 电池是否处于激活状态(Active)
  • ……

因此,即便自定义电池中不重写ReadWrite,也能对自定义电池的基本状态实现序列化和反序列化。但是如果自定义电池里出现了一个GH_Component中不包含的属性,那么其默认的序列化规则就无法将它写入 .gh 文件中了,自然也没办法从 .gh 读取该属性了。

让我们来看下面的例子:

这是一个可以把每次输入的文字不断拼接的电池,还附带了一个重置按钮。


可以看到这个电池在这个 gh 文件保存关闭再打开之后,原来存储在 myMessage 属性中的字符串值没能够成功存储。(电池输出端的 “Hello, World” 在关闭文件再次打开时消失了。)

这种情况下,在与其它人分享交流 .gh 文件的时候会变得十分不方便,因为别人再打开 .gh 文件时,电池的“状态”与它在被保存的时候的状态是不一致的。

gif中电池关键代码如下

public class ReadAndWrite : GH_Component
{// 其他电池的函数省略,比如Guid, 构造函数等string myMessage = "";  // 自定义电池的额外属性,用于存储字符串。protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager){pManager.AddTextParameter("Message", "M", "", GH_ParamAccess.item);Params.Input[0].Optional = true;pManager.AddBooleanParameter("Reset", "R", "", GH_ParamAccess.item, false);}protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager){pManager.AddTextParameter("Result", "S", "", GH_ParamAccess.item);}protected override void SolveInstance(IGH_DataAccess DA){bool resetBtn = false;if (!DA.GetData(1, ref resetBtn)) return;if (resetBtn){myMessage = string.Empty;return;}string msg = string.Empty;if (!DA.GetData(0, ref msg)) return;if (!string.IsNullOrWhiteSpace(msg)) myMessage += msg;DA.SetData(0, myMessage);}
}

重写Read()和Write()

要把自定义电池的属性(状态)存储在 .gh 文件中,就需要重写其默认的 ReadWrite 方法 —— Write用来实现序列化,Read用来实现反序列化。

在重写的函数体内,使用传入的参数 writerreader 分别来进行数据的存储和读取。这里可以存储常用的简单数据类型,包括 BooleanByteIntDoubleString 等,也可以储存一些特定的Grasshopper特有的数据类型,比如IntervalPlane等。对应的序列化和反序列化操作需要调用的函数分别是以Set开头的和Get开头的函数。比如对于整形数据,对应的序列化和反序列化操作函数分别是 writer.SetInt32reader.GetInt32

要实现对于上一节介绍的 myMessage 属性的序列化/反序列化操作,就需要使用到字符串的序列化。下面是其代码的例子。

public override bool Write(GH_IWriter writer)
{// 将变量myMessage的内容存入至gh文件的数据表中,并且给这个内容起名叫 "MyMessage"// 名字会在反序列化时用到,从数据表中取出时需要通过名字来获取writer.SetString("MyMessage", myMessage); return base.Write(writer);
}
public override bool Read(GH_IReader reader)
{// 一定要先确定数据表中有没有存在这个名字的项,否则会报I/O错误if (reader.ItemExists("MyMessage"))// 从gh文件数据表中获取名为MyMessage的数据,并转为string,存入变量中myMessage = reader.GetString("MyMessage");return base.Read(reader);
}

可以看到,在重写了这两个函数后,自定义电池已经可以“记住”自己在 .gh 文件被保存时的状态,并且在其被打开时再次恢复上次被保存的状态了。

Read()和Write()在什么时候被GH调用

Read仅仅会在 .gh 文件被打开时调用。当一个 .gh 文件被打开时,Grasshopper会使用反序列化规则在内存中挨个创建电池:先会按照 默认构造函数 创建电池的实例,然后调用 Read 函数,其内部需要包含给其他并不存在于默认构造函数中的属性 赋值。上例中的

    myMessage = reader.GetString("MyMessage");

就是给 myMessage 这个不存在于默认构造函数中的属性进行赋值。这样以来,当序列化完成之后,电池的各个自定义属性的值就会回到 .gh 文件被保存时的状态。Read函数是自定义电池类实例创建完成之后调用的。

对应的,Write函数会在每次 .gh 文件保存时被调用,用于存储自定义电池的各个属性(状态)。一个属性只有在被保存了之后,才能被成功读取,否则就会在Grasshopper打开文件时报I/O错误。大家可以尝试将上例中的 if (reader.ItemExists(...)) 判断语句拿掉,并且试图读取一个压根不存在的名字对应的值,看看在文件打开时会出现什么样的错误吧。(没错就是下面这个框)

总之,.gh 文件就好似一个数据库,而 ReadWrite 这两个函数就是电池与这个数据库之间沟通的桥梁。通过它们俩,内存中的电池实例中的数据才能被永久化地存储于 .gh 文件中。

本次关于电池的序列化与反序列化内容就介绍到这里,其中有未详尽之处,欢迎大家留言交流。

【Grasshopper基础8】电池的序列化与反序列化 Serilization of Grasshopper Component相关推荐

  1. Go进阶(7): JSON 序列化和反序列化

    1. json序列化和反序列化基础 json数据的序列化和反序列化是一种非常常见的方式,尤其是在http/rcp的微服务调试中. 基础语法 在 Go 中我们主要使用官方的 encoding/json  ...

  2. c语言 ipc 参数 序列化,浅谈IPC通信之序列化与反序列化(三)

    由于进行通信肯定要涉及数据的处理,所以我们需要先了解两个基础的概念,序列化和反序列化. 定义 序列化:将对象转化为可保存的字节序列(注意是对象): 反序列:将字节序列恢复为对象的过程. 序列化和反序列 ...

  3. 【重难点】【Java基础 04】值传递和引用传递、序列化和反序列化

    [重难点][Java基础 04]值传递和引用传递.序列化和反序列化 文章目录 [重难点][Java基础 04]值传递和引用传递.序列化和反序列化 一.值传递和引用传递 1.对比 二.序列化 1.基本概 ...

  4. 夯实Java基础系列22:一文读懂Java序列化和反序列化

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  5. 【Grasshopper基础6】输入/输出参数可变的电池 / 如何让电池支持参数增加和减少

    相信大家一定在Grasshopper中见过输入或者输出参数可以自由变化的电池,例如,笔者常用的电池"Entwine"就可以在电池的输入端添加一个参数或者减少参数,用来支持更多的电池 ...

  6. 【Grasshopper基础12】打造自定义可复用的有按钮电池外观模版

    作者:"咕咕咕?下一篇马上就写好了" 上一篇[基础11]向大家介绍了怎么在Grasshopper里制作自己的带有按钮的电池外观.从反馈来看,挺多读者对这个例子十分感兴趣,同时也私信 ...

  7. 【Grasshopper基础5】在GH里看基金? —— 简单电池项目实战

    经过前面[Grasshopper基础1~4]的介绍,相信读者已经了解了如何在Visual Studio里创建电池.如何获取数据.如何传出数据. 那么在了解这些原理之后,就让我们来一起实现一个小的项目, ...

  8. ProtoBuf的序列化和反序列化(基础库)

    内容说明: 说明下什么是ProtoBuf ProtoBuf的序列化和反序列化 ProtoBuf的优势 前后端使用ProtoBuf交互 ProtoBuf简介: Google 的 ProtoBuf ==& ...

  9. Java基础-序列化与反序列化

    序列化和反序列化在面试中也经常考查,下面就总结一下 Java 中的序列化和反序列化. 什么是序列化和反序列化? 序列化是将 Java 对象转换成与平台无关的二进制流,而反序列化则是将二进制流恢复成原来 ...

最新文章

  1. 整理下.net分布式系统架构的思路
  2. 3D图形学的线性代数的通俗解释。
  3. 雷鸣----总结下男人30岁之前要知道的事
  4. 屏蔽Crash 提示框的两种方式
  5. SVN更新的时候报断言失败解决办法
  6. Table阿里云mysql_数据同步-从MySQL到Tablestore-阿里云开发者社区
  7. bzoj 4372 烁烁的游戏 —— 动态点分治+树状数组
  8. 课程设计旅游景点咨询系统
  9. c++学习————VC报错解决方案(vc2013)
  10. 【操作系统实验】设备驱动(Linux环境下)
  11. 如何用保险保障自己的一生?
  12. c语言表达式判断语法错误题,C语言数据类型与表达式习题及答案.doc
  13. 蓝牙音频编码简介 - SBC、AAC、AptX、LDAC、LHDC
  14. 第2阶段 第12讲 XMLHTTP协议
  15. require(): open_basedir restriction in effect错误解决
  16. JAVA计算机毕业设计抑郁症患者博客交流平台Mybatis+源码+数据库+lw文档+系统+调试部署
  17. OpenJudge 4124 海贼王之伟大航路 深搜剪枝
  18. yolov5 | 移动端部署yolov5s模型
  19. 我对spring springcloud的简单理解
  20. 四大亮点不容错过,TDengine 开发者大会全议程公布!

热门文章

  1. tcp/ip 端口号有哪些
  2. EPSON ESC/POS打印机指令
  3. JavaScript 10进制转换为类似‘0x00d5’格式的16进制
  4. 【web课程设计】HTML+CSS仿QQ音乐网站
  5. Storm_Storm主要特点
  6. mac OS 下的开源工具 macports
  7. Hadoop入门 集群崩溃的处理方法
  8. maven多模块依赖导入失败以及私服下载包卡死
  9. java 雷达图_Android雷达图(蜘蛛网图),自定义view之雷达图,正五边雷达图,分数图...
  10. 国产CI/CD工具Commander