有效地从MemoryStream反序列化不同的对象类型

时间:2014-02-04 04:00:03

标签: c# generics

我正在尝试从MemoryStream手动反序列化对象,但MemoryStream中将包含不同的对象类型,我需要根据对象类型调用适当的方法。例如,这就是MemoryStream格式化的方式(对象类型然后是数据,重复):

[object type (uint)][object data (variable length)][object type (uint)][object data (variable length)][object type (uint)][object data (variable length)]

给定对象类型,我知道该对象类型需要多少数据。我遇到的问题是找出一种有效的方法来读取数据。

一种方法是使用这样的开关语句:

switch (objectType) {
    case 0:
        SomeClass.LoadFromMemoryStream(memoryStream);
        break;
    case 1:
        SomeOtherClass.LoadFromMemoryStream(memoryStream);
        break;
    case 2:
        EvenAnotherClass.LoadFromMemoryStream(memoryStream);
        break;
    ...
}

每个不同的类显然需要自己的方法来加载来自内存流的数据并推进指针,但是许多字节适合于该对象类型。

当有数百种类型的对象可以通过这种方式加载时,这似乎很难维护,如果对于流中的每个对象,它必须迭代一个包含数百种类型的case语句来确定调用

我怀疑我可以使用泛型来执行此操作,但不了解如何设置类和方法来支持它。 switch语句是最好的方法吗?如果没有,那是什么?

2 个答案:

答案 0 :(得分:0)

在我看来,我会做以下事情。 1.定义界面,

public interface ISerializableType
{
    uint TypeIdentity { get; }

    void InitFromStream(Stream stream);

    void ToStream(Stream stream);
}

2.提供实现此接口所需的所有类型。 3.创建工厂类,注册需要支持的所有对象类型

private IDictionary<uint, System.Type> _objectMap = new Dictionary<uint, System.Type>();

4.当从流中读取信息时,首先检查类型标识,然后检查您的容器以查看是否可以支持它,如果可以,然后获取类型并创建一个新的对象

5.将新对象保存到ISerializableType,并调用InitFromStream方法。

var typeIdentity = ReadIdentityFromStream(stream);
        if(_objectMap.ContainsKey(typeIdentity)){
            var type = _objectMap[typeIdentity];
            var obj = System.Activator.CreateInstance(type);
            var iSerializable = obj as ISerializableType;
            if (null != iSerializable) iSerializable.InitFromStream(stream);
        };

我希望它有所帮助。

答案 1 :(得分:0)

关于效率。检查protobuf

关于这个问题。保存/加载状态时,不应单独使用对象数组。它应该是一个完整的类型,它在自行反序列化时执行所有必要的步骤。

例如,反序列化

object[] mydata;

需要一个switch case或运行一个方法来检测对象的类型(长而难以维护的切换),你实际上可以利用属性来告诉如何处理哪个对象,但是..

考虑一下

public class Level
{
    public IItem[] Item {get; set;}
    public IRoom[] Room {get; set;}
    public IMonster[] Monster {get; set;}
    ...
}

public class ItemBook: IItem
{
    public string Name
    {
        set { /* this code will be automatically executed during deserialization */ }
    }

    public ItemBook()
    {
        /* and this code */ 
    }
}

...

反序列化Level效率更高。