在 C# 中保存字典 <int, object> - 序列化?

Saving a Dictionary<int, object> in C# - Serialization?

我有一个 c# 字典

private Dictionary<int, UserSessionInfo> userSessionLookupTable = new Dictionary<int, UserSessionInfo>();

现在我已经创建了一个字典对象

this.userSessionLookupTable.Add(userSessionInfoLogin.SessionId, userSessionInfoLogin);

现在我想要一个通用方法来将字典序列化和反序列化为字节数组。 喜欢

public static void Serialize(Dictionary<int, object> dictionary, Stream stream)
{
 //Code here
}

public static static Dictionary<int, object> Deserialize(Stream stream)
{
 //Code here
}

谁能帮我解决这个问题?

除非您想构建自己的完全自定义序列化程序,否则您需要使用内置 serialization structure

字典和所有引用的类型必须实现内置的序列化结构,这需要 类 用正确的属性装饰,即 [Serializable], or [DataContact],并且由于对象无法实现它,所以你可以'不能直接序列化,需要改成可序列化的类型

For Binary Serialization

有关详细信息,请查看 BinaryFormatter

这是一个可能的解决方案:

public void Serialize(Dictionary<int, UserSessionInfo> dictionary, Stream stream)
{
    BinaryWriter writer = new BinaryWriter(stream);
    writer.Write(dictionary.Count);
    foreach (var obj in dictionary)
    {
        writer.Write(obj.Key);
        writer.Write(obj.Value);
    }
    writer.Flush();
}

public Dictionary<int, UserSessionInfo> Deserialize(Stream stream)
{
    BinaryReader reader = new BinaryReader(stream);
    int count = reader.ReadInt32();
    var dictionary = new Dictionary<int, UserSessionInfo>(count);
    for (int n = 0; n < count; n++)
    {
        var key = reader.ReadInt32();
        var value = reader.ReadString();
        dictionary.Add(key, value);
    }
    return dictionary;                
}

但您仍然需要 UserSessionInfo ToString() 转换器;


For XML Serialization

创建示例class 会话

public class Session
{
    [XmlAttribute]
    public int SessionID;
    [XmlAttribute]
    public UserSessionInfo SessionInfo;
}

然后你可以创建XmlSerializer如果你想把它序列化为XML

XmlSerializer serializer = new XmlSerializer(
    typeof(Session[]),
    new XmlRootAttribute() { ElementName = "sessions" }
);

现在您可以序列化或反序列化了。

序列化:

serializer.Serialize(
    stream, 
    dict.Select(kv => new Session(){SessionID = kv.Key, SessionInfo = kv.Info}).ToArray()
);

反序列化:

var deserialized = (
    (Session[])serializer.Deserialize(stream)
).ToDictionary(i => i.id, i => i.info);

但是您需要在 UserSessionInfo 中使用 ToString() 方法才能将其存储在 XML.

而 XML 可能如下所示:

<sessions>
    <session id='int_goes_here' value='string_goes_here'/>
</sessions>

希望这对您有所帮助。

您可以为此目的使用 MemoryStream,除非您不想创建文件。但是对于序列化方法,如果您不想 return 一个值,您应该将 stream 参数标记为 [Out].

public static void Serialize(Dictionary<int, object> dictionary, [Out] Stream stream)
{
    stream = new MemoryStream();
    new BinaryFormatter().Serialize(stream, dictionary);
}

public static Dictionary<int, object> Deserialize(Stream stream)
{
    return (Dictionary<int, object>)new BinaryFormatter().Deserialize(stream);
}

这将执行二进制序列化。

编辑:

要将其作为字节数组获取,您只需将流 returned 从 Serialize() 方法转换为 MemoryStream,然后对其调用 .ToArray() .

这是一个例子:

MemoryStream outputStream;
Serialize(your dictionary here, outputStream);
byte[] bytes = outputStream.ToArray();

试试这个....

    public static void Serialize<Object>(Object dictionary, Stream stream)
    {
        try // try to serialize the collection to a file
        {
            using (stream)
            {
                // create BinaryFormatter
                BinaryFormatter bin = new BinaryFormatter();
                // serialize the collection (EmployeeList1) to file (stream)
                bin.Serialize(stream, dictionary);
            }
        }
        catch (IOException)
        {
        }
    }

    public static Object Deserialize<Object>(Stream stream) where Object : new()
    {
        Object ret = CreateInstance<Object>();
        try
        {
            using (stream)
            {
                // create BinaryFormatter
                BinaryFormatter bin = new BinaryFormatter();
                // deserialize the collection (Employee) from file (stream)
                ret = (Object)bin.Deserialize(stream);
            }
        }
        catch (IOException)
        {
        }
        return ret;
    }
    // function to create instance of T
    public static Object CreateInstance<Object>() where Object : new()
    {
        return (Object)Activator.CreateInstance(typeof(Object));
    }

用法...

        Serialize(userSessionLookupTable, File.Open("data.bin", FileMode.Create));
        Dictionary<int, UserSessionInfo> deserializeObject = Deserialize<Dictionary<int, UserSessionInfo>>(File.Open("data.bin", FileMode.Open));

我在上面的代码中使用了 'Object' 来满足您的要求,但我个人会使用 'T',它通常表示 C# 中的通用对象

也许回答有点晚,但根据我的经验,这是一个实用且更通用的答案:如果您想要快速简单的东西或者对数据大小的需求不多,请使用简单的 JSON 序列化或表现。如果您还想要 space 高效、快速和跨平台的东西,请使用 Google Protocol Buffers。

JSON

string output = JsonConvert.SerializeObject(myObject);
var copyOfMyObject = JsonConvert.DeserializeObject<MyObject>(output);

有很多方法可以control the serialisation and use streams and so on

Json.Net also supports dictionaries too.

Protobuf

在c#中有两种使用protobuf的方式:Using .proto message definitions and generate code or reflection based approach using your class definitions and attributes。这取决于您的项目,但我个人更喜欢消息定义。

请注意,您可能必须在序列化和反序列化之前和之后进行自己的修改才能与 Dictionary 一起使用。

基于消息定义:使用 proto3

.proto 文件:

message Person {
  int32 id = 1;
  string name = 2;
}

使用Google Protobuf生成代码:

protoc --csharp_out=$DST_DIR $SRC_DIR/person.proto

Serialise / deserialise using generated classes:

Person john = ...;
john.WriteTo(stream);
var copyOfJohn = Person.Parser.ParseFrom(stream);

另外,一个简短的说明让您知道 proto3 is the capability of using JSON 可能有一个鲜为人知的功能。

基于反射:Protobuf-net

这是一个简单的例子(从protobuf-net page复制)

[ProtoContract]
class Person {
    [ProtoMember(1)]
    public int Id {get;set;}
    [ProtoMember(2)]
    public string Name {get;set;}
}
Serializer.Serialize(file, person);
newPerson = Serializer.Deserialize<Person>(file);

二进制、文本、流,天哪!

抱歉,我有点忽略了关于 'Binary' 序列化的问题(并且不是一个特定的 BinaryFormatter 问题),因为有很多方法可以使用流来处理流入和流出的数据出一个过程。 C# 流、reader 和 writer 以及其他 System.IO APIs 都有很好的文档记录。