代理类是否可以包含对原始类的引用

本文关键字:原始 引用 是否 代理 包含 | 更新日期: 2023-09-27 18:24:10

我正在尝试为名为Transform的第三方类创建代理。我只需要序列化它的一些公共成员,包括对另一个此类实例的一些引用,并公开Transforms的内部列表。所以我为它编写了代理,但我不确定是否可以在代理的字段上定义[ProtoMember]属性,这些字段属于Transform类型。还是应该是TransformSurrogate?现在我的代码是:

[ProtoContract(AsReferenceDefault = true)]
public class TransformSurrogate {
    [ProtoMember(1)]
    Vector3 localPosition { get; set; }
    [ProtoMember(2)]
    Vector3 localScale { get; set; }
    [ProtoMember(3)]
    Quaternion localRotation { get; set; }
    [ProtoMember(4, AsReference = true)]
    Transform parent { get; set; }
    [ProtoMember(5, AsReference = true)]
    List<Transform> children { get; set; }
    public static explicit operator TransformSurrogate(Transform transform) {
        if (transform == null) return null;
        var surrogate = new TransformSurrogate();
        surrogate.localPosition = transform.localPosition;
        surrogate.localRotation = transform.localRotation;
        surrogate.localScale = transform.localScale;
        surrogate.parent = transform.parent;
        surrogate.children = new List<Transform>();
        for (int i = 0; i < transform.childCount; ++i) {
            surrogate.children.Add(transform.GetChild(i));
        }
        return surrogate;
    }
    public static explicit operator Transform(TransformSurrogate surrogate) {
        if (surrogate == null) return null;
        var transform = new GameObject().transform;
        transform.localPosition = surrogate.localPosition;
        transform.localRotation = surrogate.localRotation;
        transform.localScale = surrogate.localScale;
        transform.parent = (Transform) surrogate.parent;
        foreach (var child in surrogate.children) {
            child.parent = transform;
        }
        return transform;
    }
}

不要太关注Vector3Quaternion类——它们是容易序列化的结构。因此,我为Transform类型定义了自己的RuntimeTypeModel,如下所示:

Model.Add(typeof(Transform), false).SetSurrogate(typeof(TransformSurrogate));

然而,我在反序列化过程中遇到了一个错误,告诉我Protobuf无法在类之间转换。我认为这是因为在代理类中混合了原始类,但我不确定。

代理类是否可以包含对原始类的引用

对于某些数据类型,是的,它会起作用,我现在正在做完全相同的事情(为Unity3D转换编写代理)。早些时候,我在MeshSurrogate上进行了测试。以下是代码的开始方式。。。

[ProtoContract(AsReferenceDefault = true)]
    [ProtoSurrogate(typeof(Mesh))]
    sealed class MeshSurrogate {
        [ProtoMember(1)]
        Matrix4x4[] bindposes;
        [ProtoMember(2)]
        BoneWeight[] boneWeights;
/* Lots more follows */

(ProtoSurrogateAttribute是自定义的……它可以满足您的期望)它可以很好地序列化和反序列化所有数据类型的原始非代理类型的字段。

不过,Transform变得更加有趣。这是一个潜在的问题-据报道,AsReference与代孕者打得不好-https://code.google.com/p/protobuf-net/issues/detail?id=352太糟糕了,因为这是我们Unity序列化策略的核心。

如果我能做到这一点,我会更新的。

更新:事实证明,这相当复杂。

我得到的解决方案是,基本上任何继承UnityEngine.Object的东西都会得到一个代理,它只包含3个成员——一个instanceIdBeforeSerialization(使用UnityEngine.Object.GetInstanceID()获得)、一个"shell"和一个"data"。只有当此代理是此序列化过程中第一个遇到的代理时,才会填充shell和数据,否则它们为null。shell负责实例化对象,并负责在[OnDeserialized]方法中填充每个对象的数据。当shell创建一个对象时,它会将其存储在一个表中,该表具有从旧实例id到新实例id的映射,因此当任何代理转换为原始类型时,它只需要在表中搜索它的新对象。因为shell被放置在流的早期,所以在需要在对象图中引用它们之前,所有对象至少都已初始化。

不幸的是,我无法让Data类直接存储对Unity对象的引用,但这是一个库,因此最大的便利在于用户,而不是作者。

现在这些问题都解决了,看起来这种方法会很好地发挥作用。我会看看我的雇主是否允许它进入资产商店。

更新:这将在完成后进入资产存储。有很多代孕者需要先添加,所以可能需要一段时间。