【问题标题】:Protobuf in compiled Unity build throws InvalidOperationException: No serializer defined for type编译的 Unity 构建中的 Protobuf 抛出 InvalidOperationException:没有为类型定义序列化程序
【发布时间】:2014-04-08 18:49:12
【问题描述】:

我正在使用 Unity 的 protobuf-net 来加载关卡的数据。序列化/反序列化在编辑器中运行时有效,但是当我编译并创建构建然后运行它时,我在反序列化时遇到以下异常:

InvalidOperationException: No serializer defined for type:
System.Collections.Generic.KeyValuePair`2[[System.String, 
    mscorlib, Version=2.0.5.0, Culture=neutral, 
    PublicKeyToken=7cec85d7bea7798e],[System.Int32, mscorlib, Version=2.0.5.0, 
    Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]

我不确定 protobuf-net 在使用它们进行反序列化之前如何分析类型,所以我不确定如何解决这个问题。如果有人知道可能导致此问题的原因,我将非常感谢您的解释。我可以自己定义反序列化方法吗?某种类型的自定义反序列化器之类的东西?谢谢!

编辑:

这是我认为导致问题的课程:

[ProtoContract]
public class LevelData
{
    [ProtoMember(1)]
    public string Background = "";
    [ProtoMember(2)]
    public string Name = "";
    [ProtoMember(3)]
    public Dictionary<string, int> PreloadInfo {get; private set;}
    [ProtoMember(4)]
    public List<string> RoomFiles { get; private set; }

    public LevelData()
    {
        PreloadInfo = new Dictionary<string, int>();
        RoomFiles = new List<string>();
    }
}

运行 protogen 后,我注意到 Unity 和我创建的编译后的 dll 之间的 String 和 Int32 的版本不匹配。 Unity 尝试使用 2.0.5.0 版本反序列化,而我编译的 dll 使用 2.0.0.0 版本。我假设这就是反序列化失败的原因。这是 protogen 的输出:

Adding System.Collections.Generic.KeyValuePair`2[[System.String, mscorlib,
  Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Int32, msc
  orlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]...
  Adding System.Collections.Generic.KeyValuePair`2[[System.String, mscorlib, Versi
  on=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, ms
  corlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]...

用于反序列化的代码:

var serializer = GnomingSerializer.Create ();

int startMillis = System.Environment.TickCount;

TextAsset levelDoc = (TextAsset)Resources.Load(path);
MemoryStream mStream = new MemoryStream(levelDoc.bytes);

//LevelData levelData = Serializer.Deserialize<LevelData>(mStream);
LevelData levelData = new LevelData();
serializer.Deserialize (mStream, levelData, typeof(LevelData));

【问题讨论】:

  • 切换到类似 protobuf-csharp-port 的东西会帮助这种情况吗? code.google.com/p/protobuf-csharp-port
  • 您是否使用运行时处理?还是您使用的是protogen工具?基本上:我怎么能重现它?
  • 我正在使用运行时序列化和反序列化数据。我也在为 Wii U 开发,这仅在我在硬件上运行时才会发生,因此这可能与 Unity 在硬件上提供的 API 子集有关。
  • 我在移动设备上,但我建议在此处使用预编译器 - 搜索“引入 protobuf-net 预编译器 protogen”或类似内容
  • 不走运。我使用了预编译器并切换了我的代码,但我仍然遇到同样的异常。有什么办法可以强制预编译器包含 KeyValuePair 的序列化程序?

标签: c# unity3d protobuf-net


【解决方案1】:

从 cmets 看来,您的树中的根类型听起来像是字典。在 DTO 程序集的静态分析期间,它无法识别这一点 - 因此不考虑 KVP 场景(其中有无限多)。您可以在不更改现有代码的情况下解决此问题 - 只需添加分析工具可以找到的内容。例如,如果您将Dictionary&lt;string, MyType&gt; 序列化为根对象,只需添加:

[ProtoContract]
public class NeverUsed {
    [ProtoMember(1)]
    public Dictionary<string,MyType> Dummy;
}

(现在重新运行 protogen 等)

这应该足以让静态分析工具找到它并准备适用于KeyValuePair&lt;string,MyType&gt;的策略

另一种方法是始终将您自己的类型序列化为模型的根 - 基本上从 NeverUsed 实例开始。

【讨论】:

  • 我在我的原始帖子中添加了一个示例类。我不确定我完全理解“树中的根类型”是什么意思。你能稍微澄清一下吗?感谢大家的帮助!
  • @Spencer 的“根类型”,我的意思是这个东西实际上会传递给序列化,或者你传递给反序列化的 T/Type。如果那是 LevelData,那么你有 应该 工作 - 你能确认 protogen 的输出吗?并且您正在引用和使用 protogen 的输出?
  • 我正在使用我编写的程序来生成游戏中使用的序列化数据。我没有使用我生成的 protogen dll 来重新生成序列化数据。这可能是我看到的问题吗?在使用 protogen dll 反序列化时,使用常规的 protobuf-net 序列化会导致问题吗?
  • @Spencer 网络上的数据应该是相同的:所有 protogen 所做的只是将所有分析移动到一个固定的时间点(通常是一个构建步骤)而不是运行时。
  • 我在原帖中放了一个 protogen 输出的例子。
猜你喜欢
  • 1970-01-01
  • 2013-11-17
  • 1970-01-01
  • 2022-01-04
  • 1970-01-01
  • 2012-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多