翼度科技»论坛 编程开发 .net 查看内容

Unity中的SerializeReference使用简介

7

主题

7

帖子

21

积分

新手上路

Rank: 1

积分
21
Unity 默认可以序列化值类型, Serializable属性修饰的类型, 派生自UnityEngine.Object的类型, 通常这些类型已经足以供日常使用了.
但是有时我们希望在编辑器面板上序列化一个接口或者抽象类, 则需要用到 SerializeReference属性.
假定我们有一个接口IEatable, 并实现了两个类Bread和Bun:
  1. public interface IEatable
  2. {
  3.     int Calorie { get; }
  4. }
  5. public class Bread : IEatable
  6. {
  7.     [field: SerializeField]
  8.     public int Calorie { get; private set; } = 100;
  9. }
  10. public class Bun : IEatable
  11. {
  12.     public enum Fillings
  13.     {
  14.         [InspectorName("肉馅")]
  15.         Meat,
  16.         [InspectorName("韭菜鸡蛋")]
  17.         LeekAndAgg,
  18.     }
  19.     [field: SerializeField]
  20.     public int Calorie { get; private set; } = 200;
  21.     [field: SerializeField]
  22.     public Fillings Filling { get; private set; }
  23. }
复制代码
相应的, 我们定义了一个餐盘类去盛放食物Plate:
  1. [CreateAssetMenu(menuName = "Plate for Food")]
  2. public class Plate : ScriptableObject
  3. {
  4.     private IEatable _eatable;
  5.     public IEatable Eatable { get => _eatable; set => _eatable = value; }
  6. }
复制代码
在Unity编辑器内右键新建一个Plate, 可见Inspector面板上没有显示Eatable字段.

此时我们为_eatable字段添加SerializeReference属性.
注意, 添加SerializeReference后, 即使字段是私有的, 也无需添加SerializeField属性, 二者同有将私有字段序列化的能力.
  1. [CreateAssetMenu(menuName = "Plate for Food")]
  2. public class Plate : ScriptableObject
  3. {
  4.     [SerializeReference]
  5.     private IEatable _eatable;
  6.     public IEatable Eatable { get => _eatable; set => _eatable = value; }
  7. }
复制代码
添加SerializeReference属性后, Inspector面板上已经可以显示Eatable字段了, 但是由于此时_eatable字段的值为null, 所以并没有显示其他信息.
SerializeReference属性允许字段为null, 这点与默认序列化行为不同, 默认序列化会自动实例化一个值

接下来我们在Plate中定义一个方法ServeBread, 将_eatable字段设置为Bread实例, 并使用ContextMenuItem属性将此方法设置为_eatable字段的上下文菜单:
  1.     [ContextMenuItem("盛放面包", "ServeBread", order = 0)]
  2.     [ContextMenuItem("盛放包子", "ServeBun", order = 1)]
  3.     [SerializeReference]
  4.     private IEatable _eatable;
  5.     ...
  6.    
  7.     private void ServeBread() => _eatable = new Bread();
  8.     private void ServeBun() => _eatable = new Bun();
  9.     ...
复制代码
回到Unity编辑器, 此时我们就可以右键点击Eatable字段并在弹出菜单中选择一项来为_eatable字段赋值了.
添加[field: SerializeField]后, 属性也可以像字段一样被序列化, 但是其label会显示为k__BackingField, 如果不希望这种现象,可以将属性转化为完整属性并为对应的私有字段添加SerializeField.

用文本编辑器打开Plate.asset文件, 可以看到使用SerializeReference属性进行序列化后的内容, 可以对比一下普通的序列化方式.

其中, type记录了字段内容的具体类型class, 所在命名空间ns, 所在的程序集asm. 而data则记录了实例的可序列化字段及内容.
ContextMenuItem方式只是为了演示, 合理的做法应该是自行实现对应的PropertyDrawer.
SerializeReference还可以修饰List和T[], 具体情况可以查看Unity官方文档, 这里就不赘述了.

来源:https://www.cnblogs.com/liougouren/p/18023731
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具