【问题标题】:Can surrogate class contain references to original class代理类可以包含对原始类的引用吗
【发布时间】:2014-09-24 15:00:21
【问题描述】:

我正在尝试为名为@9​​87654321@ 的第三方类创建代理项。我只需要序列化它的一些公共成员,包括对另一个此类实例的一些引用并公开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 无法在类之间进行转换。我认为这是因为在代理类中混合了原始类,但我不确定。

【问题讨论】:

  • 这在依赖于非核心类型的复杂类型的上下文中很难回答;你有一个例子来说明只使用简单的本地类型的问题吗?
  • @MarcGravell 现在我正在尝试在更简单的环境中对这种情况进行建模,但是如果您想知道 Vector3 和 Quaternion 类型是什么 - 您可以跳过它们,因为它们是简单的结构并且我成功地序列化了它们.我现在主要关注的是 Transform 类。 Transform 是 Unity3D 内置类型,如果有帮助的话。

标签: c# serialization unity3d protocol-buffers protobuf-net


【解决方案1】:

对于某些数据类型,是的,它会起作用,我现在正在做同样的事情(为 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 个且仅 3 个成员的代理项 - 一个 instanceIdBeforeSerialization(通过 UnityEngine.Object.GetInstanceID() 获得)、一个“shell”和一个“数据”。只有在此序列化过程中首先遇到此代理项时才会填充 shell 和数据,否则它们为空。 Shell 负责实例化对象,以及在 [OnDeserialized] 方法中填充它们的数据。当 shell 创建一个对象时,它将它存储在一个表中,该表具有从它的旧实例 id 到它的新实例 id 的映射,因此当任何代理被强制转换为原始类型时,它只需要在表中搜索它的新对象。由于 shell 较早地放置在流中,因此至少在需要在对象图中引用它们之前对所有对象进行初始化。

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

既然问题已经解决,看起来这种方法会很有效。我会看看我的雇主是否允许它去资产商店。

更新: 这将在完成后进入资产商店。要先添加很多代理项,所以可能需要一段时间。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-26
    • 1970-01-01
    • 1970-01-01
    • 2018-05-09
    • 2010-12-29
    相关资源
    最近更新 更多