C# protobuf网络和对象反序列化

C# protobuf网络和对象反序列化,c#,.net,protobuf-net,C#,.net,Protobuf Net,我正在检查protobuf net是否可以替代DataContracts。除了出色的性能外,这真是一个整洁的图书馆。我唯一的问题是.NET序列化程序没有对当前正在反序列化的内容进行任何假设。尤其是包含对类型化对象的引用的对象是一个问题 [DataMember(Order = 3)] public object Tag1 // The DataContract did contain a object which becomes now a SimulatedObject { get;

我正在检查protobuf net是否可以替代DataContracts。除了出色的性能外,这真是一个整洁的图书馆。我唯一的问题是.NET序列化程序没有对当前正在反序列化的内容进行任何假设。尤其是包含对类型化对象的引用的对象是一个问题

[DataMember(Order = 3)]
public object Tag1 // The DataContract did contain a object which becomes now a SimulatedObject
{
    get;
    set;
}
我试着用协议缓冲区模拟对象,其中有一个小的泛型助手,它将每个可能的类型存储在不同的强类型字段中

这是处理反序列化为许多不同的不相关类型的字段的推荐方法吗

下面是一个模拟对象的示例代码,它最多可以容纳10种不同的类型

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using ProtoBuf;
using System.Diagnostics;

[DataContract]
public class SimulatedObject<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10>
{
    [DataMember(Order = 20)]
    byte FieldHasValue; // the number indicates which field actually has a value

    [DataMember(Order = 1)]
    T1 I1;

    [DataMember(Order = 2)]
    T2 I2;

    [DataMember(Order = 3)]
    T3 I3;

    [DataMember(Order = 4)]
    T4 I4;

    [DataMember(Order = 5)]
    T5 I5;

    [DataMember(Order = 6)]
    T6 I6;

    [DataMember(Order = 7)]
    T7 I7;

    [DataMember(Order = 8)]
    T8 I8;

    [DataMember(Order = 9)]
    T9 I9;

    [DataMember(Order = 10)]
    T10 I10;

    public object Data
    {
        get
        {
            switch(FieldHasValue)
            {
                case 0: return null;
                case 1: return I1;
                case 2: return I2;
                case 3: return I3;
                case 4: return I4;
                case 5: return I5;
                case 6: return I6;
                case 7: return I7;
                case 8: return I8;
                case 9: return I9;
                case 10: return I10;
                default:
                    throw new NotSupportedException(String.Format("The FieldHasValue field has an invlaid value {0}. This indicates corrupt data or incompatible data layout chagnes", FieldHasValue));
            }
        }
        set
        {
            I1 = default(T1);
            I2 = default(T2);
            I3 = default(T3);
            I4 = default(T4);
            I5 = default(T5);
            I6 = default(T6);
            I7 = default(T7);
            I8 = default(T8);
            I9 = default(T9);
            I10 = default(T10);


            if (value != null)
            {
                Type t = value.GetType();
                if (t == typeof(T1))
                {
                    FieldHasValue = 1;
                    I1 = (T1) value;
                }
                else if (t == typeof(T2))
                {
                    FieldHasValue = 2;
                    I2 = (T2) value;
                }
                else if (t == typeof(T3))
                {
                    FieldHasValue = 3;
                    I3 = (T3) value;
                }
                else if (t == typeof(T4))
                {
                    FieldHasValue = 4;
                    I4 = (T4) value;
                }
                else if (t == typeof(T5))
                {
                    FieldHasValue = 5;
                    I5 = (T5) value;
                }
                else if (t == typeof(T6))
                {
                    FieldHasValue = 6;
                    I6 = (T6) value;
                }
                else if (t == typeof(T7))
                {
                    FieldHasValue = 7;
                    I7 = (T7) value;
                }
                else if (t == typeof(T8))
                {
                    FieldHasValue = 8;
                    I8 = (T8) value;
                }
                else if (t == typeof(T9))
                {
                    FieldHasValue = 9;
                    I9 = (T9) value;
                }
                else if (t == typeof(T10))
                {
                    FieldHasValue = 10;
                    I10 = (T10) value;
                }
                else
                {
                    throw new NotSupportedException(String.Format("The type {0} is not supported for serialization. Please add the type to the SimulatedObject generic argument list.", t.FullName));
                }
            }
        }
    }
}

[DataContract]
class Customer
{
    /* 
    [DataMember(Order = 3)]
    public object Tag1 // The DataContract did contain a object which becomes now a SimulatedObject
    {
        get;
        set;
    }
    */

    [DataMember(Order = 3)]
    public SimulatedObject<bool, Other, Other, Other, Other, Other, Other, Other, Other, SomethingDifferent> Tag1 // Can contain up to 10 different types
    {
        get;
        set;
    }



    [DataMember(Order = 4)]
    public List<string> Strings
    {
        get;
        set;
    }
}

[DataContract]
public class Other
{
    [DataMember(Order = 1)]
    public string OtherData
    {
        get;
        set;
    }
}

[DataContract]
public class SomethingDifferent
{
    [DataMember(Order = 1)]
    public string OtherData
    {
        get;
        set;
    }

}


class Program
{
    static void Main(string[] args)
    {
        Customer c = new Customer
        {
            Strings = new List<string> { "First", "Second", "Third" },
            Tag1 = new SimulatedObject<bool, Other, Other, Other, Other, Other, Other, Other, Other, SomethingDifferent>
                    {
                        Data = new Other {  OtherData = "String value "}
                    }
        };

        const int Runs = 1000 * 1000;
        var stream = new MemoryStream();

        var sw = Stopwatch.StartNew();

        Serializer.Serialize<Customer>(stream, c);
        sw = Stopwatch.StartNew();
        for (int i = 0; i < Runs; i++)
        {
            stream.Position = 0;
            stream.SetLength(0);
            Serializer.Serialize<Customer>(stream, c);
        }
        sw.Stop();
        Console.WriteLine("Data Size with Protocol buffer Serializer: {0}, {1} objects did take {2}s", stream.ToArray().Length, Runs, sw.Elapsed.TotalSeconds);

        stream.Position = 0;
        var newCustw = Serializer.Deserialize<Customer>(stream);

        sw = Stopwatch.StartNew();
        for (int i = 0; i < Runs; i++)
        {
            stream.Position = 0;
            var newCust = Serializer.Deserialize<Customer>(stream);
        }
        sw.Stop();
        Console.WriteLine("Read object with Protocol buffer deserializer: {0} objects did take {1}s", Runs, sw.Elapsed.TotalSeconds);

    }
}
使用系统;
使用System.Collections.Generic;
使用System.IO;
使用System.Runtime.Serialization;
使用ProtoBuf;
使用系统诊断;
[数据合同]
公共类模拟对象
{
[数据成员(顺序=20)]
byte FieldHasValue;//该数字指示哪个字段实际有值
[数据成员(顺序=1)]
T1-I1;
[数据成员(顺序=2)]
t2i2;
[数据成员(顺序=3)]
t3i3;
[数据成员(顺序=4)]
T4 I4;
[数据成员(顺序=5)]
t5i5;
[数据成员(顺序=6)]
t6i6;
[数据成员(顺序=7)]
t7i7;
[数据成员(顺序=8)]
t8i8;
[数据成员(顺序=9)]
t9i9;
[数据成员(顺序=10)]
t10i10;
公共对象数据
{
得到
{
开关(FieldHasValue)
{
案例0:返回null;
案例1:返回I1;
案例2:返回I2;
案例3:返回I3;
案例4:返回I4;
案例5:返回I5;
案例6:返回I6;
案例7:返回I7;
案例8:返回I8;
案例9:返回I9;
案例10:返回I10;
违约:
抛出新的NotSupportedException(String.Format(“FieldHasValue字段有一个Invlaed值{0}。这表示数据损坏或数据布局不兼容”,FieldHasValue));
}
}
设置
{
I1=默认值(T1);
I2=默认值(T2);
I3=默认值(T3);
I4=违约(T4);
I5=默认值(T5);
I6=默认值(T6);
I7=默认值(T7);
I8=默认值(T8);
I9=默认值(T9);
I10=默认值(T10);
if(值!=null)
{
类型t=value.GetType();
if(t==typeof(T1))
{
FieldHasValue=1;
I1=(T1)值;
}
else if(t==typeof(T2))
{
FieldHasValue=2;
I2=(T2)值;
}
else if(t==typeof(T3))
{
FieldHasValue=3;
I3=(T3)值;
}
否则如果(t==类型(T4))
{
FieldHasValue=4;
I4=(T4)值;
}
else if(t==类型(T5))
{
FieldHasValue=5;
I5=(T5)值;
}
else if(t==typeof(T6))
{
FieldHasValue=6;
I6=(T6)值;
}
else if(t==typeof(T7))
{
FieldHasValue=7;
I7=(T7)值;
}
else if(t==typeof(T8))
{
FieldHasValue=8;
I8=(T8)值;
}
else if(t==typeof(T9))
{
FieldHasValue=9;
I9=(T9)值;
}
else if(t==typeof(T10))
{
FieldHasValue=10;
I10=(T10)值;
}
其他的
{
抛出新的NotSupportedException(String.Format(“序列化不支持类型{0}。请将该类型添加到SimulatedObject泛型参数列表。”,t.FullName));
}
}
}
}
}
[数据合同]
类客户
{
/* 
[数据成员(顺序=3)]
public object Tag1//DataContract确实包含一个对象,该对象现在已成为模拟对象
{
得到;
设置
}
*/
[数据成员(顺序=3)]
公共模拟对象Tag1//最多可以包含10种不同类型
{
得到;
设置
}
[数据成员(顺序=4)]
公共列表字符串
{
得到;
设置
}
}
[数据合同]
公共类其他
{
[数据成员(顺序=1)]
公共字符串数据
{
得到;
设置
}
}
[数据合同]
公共课有些不同
{
[数据成员(顺序=1)]
公共字符串数据
{
得到;
设置
}
}
班级计划
{
静态void Main(字符串[]参数)
{
客户c=新客户
{
Strings=新列表{“第一”、“第二”、“第三”},
Tag1=新的模拟对象
{
Data=new Other{OtherData=“String value”}
}
};
const int Runs=1000*1000;
var stream=newmemoryStream();
var sw=Stopwatch.StartNew();
Serializer.Serialize(流,c);
sw=秒表。开始新();
for(int i=0;ipublic byte[] Serialize(object myObject)
{
    using (var ms = new MemoryStream())
    {
        Type type = myObject.GetType();
        var id = System.Text.ASCIIEncoding.ASCII.GetBytes(type.FullName + '|');
        ms.Write(id, 0, id.Length);
        Serializer.Serialize(ms, myObject);
        var bytes = ms.ToArray();
        return bytes;
    }
}

public object Deserialize(byte[] serializedData)
{
    StringBuilder sb = new StringBuilder();
    using (var ms = new MemoryStream(serializedData))
    {
        while (true)
        {
            var currentChar = (char)ms.ReadByte();
            if (currentChar == '|')
            {
                break;
            }

            sb.Append(currentChar);
        }

        string typeName = sb.ToString();

        // assuming that the calling assembly contains the desired type.
        // You can include aditional assembly information if necessary
        Type deserializationType = Assembly.GetCallingAssembly().GetType(typeName);

        MethodInfo mi = typeof(Serializer).GetMethod("Deserialize");
        MethodInfo genericMethod = mi.MakeGenericMethod(new[] { deserializationType });
        return genericMethod.Invoke(null, new[] { ms });
    }
}