如何从一种类型序列化/反序列化到另一种类型?

时间:2019-07-31 14:18:51

标签: c# serialization deserialization

介绍内容的小介绍:

在服务器端:

  • 我有一个装配体“ TheoreticalObjects”
  • 此程序集包含一个基类“ BaseClass”,我所有的THEORETICAL对象都从该基类派生
  • 从TheoreticalObjects.BaseClass继承的类例如: TheoreticalObjects.Tube,TheoreticalObjects.Flange,TheoreticalObjects.Caps ...

在客户端:

  • 我也有用于理论对象的组装
  • 但是我有另一个名为“ RealObjects”的程序集(专用于生成顶点)
  • 此程序集包含一个基类“ BaseClass”,我的所有REAL对象都从该基类派生
  • 从RealObjects.BaseClass继承的类例如: RealObjects.Tube,RealObjects.Flange,RealObjects.Caps ...

我想序列化服务器上​​的对象(作为TheoreticalObjects.BaseClass),通过tcp将json发送到客户端,然后反序列化json(作为RealObjects.BaseClass)。

这是我的课程:(假设我们要创建一个Tube):

// my TheoreticalObjects.BaseClass
namespace TheoreticalObjects
{
    [DataContract]
    public class BaseClass
    {
        [DataMember]
        public Guid GUID { get; set; }

        [DataMember]
        public int ID { get; set; }

        [DataMember]
        public string Designation { get; set; }

        [DataMember]
        public string Product { get; set; }

        [DataMember]
        public int IDMaterial { get; set; }

        [DataMember]
        public int Quantity { get; set; }

        [DataMember]
        public string Form { get; set; }

        protected BaseClass()
        { }
        protected BaseClass(int iD, string designation, string product, int iDMaterial, int quantity, string form) 
        {
            ID = iD;
            Designation = designation;
            Product = product;
            IDMaterial = iDMaterial;
            Quantity = quantity;
            Form = form;
        }
    }
}
// my TheoreticalObjects.Tube
namespace TheoreticalObjects
{
    [DataContract]
    public class Tube : BaseClass
    {
        [DataMember]
        public Length Diameter { get; set; }

        [DataMember]
        public Length WallThickness { get; set; }

        [DataMember]
        public Length Length { get; set; }

        public Tube() : base()
        { }

        public Tube(int iD, string designation, string product, int iDmaterial, int quantity, string form, Length diameter, Length Wallthickness, Length length)  : base(iD, designation, product, iDmaterial, quantity,form)
        {
            WallThickness = Wallthickness;
            Diameter = diameter;
            Length = length;
        }

    }
}
// my RealObjects.BaseClass
namespace RealObjects
{
    public class BaseClass
    {

        public Guid GUID { get; set; }
        public int ID { get; set; }
        public string Designation { get; set; }
        public string Product { get; set; }
        public int IDMaterial { get; set; }
        public int Quantity { get; set; }
        public string Form { get; set; }


        protected BaseClass() { }
        protected BaseClass(int iD, string designation, string product, int iDMaterial, int quantity, string form)
        {
            ID = iD;
            Designation = designation;
            Product = product;
            IDMaterial = iDMaterial;
            Quantity = quantity;
            Form = form;
        }


        public List<Face> myFaces = new List<Face>(); // faces of the mesh
        public MyMesh mesh = new MyMesh();

        public void Triangulation(TopoDS_Shape shape, double deflection)
        {
            // things ...


        myFaces = things...
            mesh = new MyMesh(myFaces);
        }


    }
}
// my RealObjects.Tube
namespace RealObjects
{
    public class Tube: BaseClass
    {

        public double diameter;
        public double Wallthickness;
        public double length;

        public Tube() : base() { }
        public Tube(int iD, string designation, string product, int iDmaterial, int quantity, string form, double diameter, double wallThickness, double length) : base(iD, designation, product, iDmaterial, quantity, form)
        {
            this.diameter = diameter;
            this.Wallthickness = wallThickness;
            this.length = length;

            Build(diameter, Wallthickness, length);
        }

        public void Build(double diameter, double Wallthickness, double length)
        {
           //things ...


           Triangulation(things...);
        }


    }
}

我的问题是,在将我的Tube序列化并发送给客户端之后,它无法正确反序列化:我得到的是RealObjects.BaseClass而不是RealObjects.BaseClass.Tube。

  • 我做了一个Binder将名称绑定到类型,但是反序列化时根本没有调用BindToType()

_______________在服务器端____________

//creating the Tube  
TheoreticalObjects.Tube c = new TheoreticalObjects.Tube(1, "Tube", "Element", 1, 1, "tube", new Length(1, UnitsNet.Units.LengthUnit.Meter), new Length(0.1, UnitsNet.Units.LengthUnit.Meter), new Length(2, UnitsNet.Units.LengthUnit.Meter));
// settings for the serializer
JsonSerializerSettings _jsonSerializerSettingsOCCServer = new JsonSerializerSettings { Formatting = Newtonsoft.Json.Formatting.Indented };
_jsonSerializerSettingsOCCServer.Converters.Add(new UnitsNetJsonConverter());
// serialization
string json = JsonConvert.SerializeObject(c, _jsonSerializerSettingsOCCServer).Replace("\r\n", "\n");
// the message that the server will send
CommunicateElement messageObject = new CommunicateElement(NetworkComms.NetworkIdentifier, json, 1234, c.Designation);

在发送邮件之后

_______________在客户端______________

消息已处理,函数将消息放入“ constructionQueue”

// settings for the deserializer
_jsonSerializerSettingsOCC = new JsonSerializerSettings {
            TypeNameHandling = TypeNameHandling.All,
            Binder = new MyBinder(),
            NullValueHandling = NullValueHandling.Ignore,
            DefaultValueHandling = DefaultValueHandling.Ignore,
            Formatting = Newtonsoft.Json.Formatting.Indented,
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        };
_jsonSerializerSettingsOCC.Converters.Add(new UnitsNetJsonConverter());
// deserialize the json (that was previously a TheoreticalObjects.Tube) into a RealObjects.BaseClass and add it to the construction queue
constructionQueue.Add(JsonConvert.DeserializeObject<RealObjects.BaseClass>(messageObject.Message, _jsonSerializerSettingsOCC));

...... ......一旦进入施工队列,我尝试创建它..... ......无需知道之后会发生什么..... ......请注意,我在寻找RealObjects.Tube,而不是RealObjects.BaseClass ..... ......

_______________ MyBinder ____________

public class MyBinder : SerializationBinder
    {
        readonly Dictionary<Type, string> typeToName = new Dictionary<Type, string>();
        readonly Dictionary<string, Type> nameToType = new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase);

        public MyBinder()
        {
            List<Type> myTypes = new List<Type>();
            Assembly[] myAssemblies = AppDomain.CurrentDomain.GetAssemblies();
            for (int i = 0; i < myAssemblies.Length; i++)
            {
                if (myAssemblies[i].GetName().Name == "RealObjects")
                {
                    foreach (Type t in myAssemblies[i].GetTypes())
                    {
                        if (t.IsSubclassOf(typeof(RealObjects.BaseClass)))
                        {
                            myTypes.Add(t);
                        }
                    }
                    break;
                }
            }

            foreach (var type in myTypes)
            {
                Map(type, type.Name);
            }
        }

        public void Map(Type type, string name)
        {
            this.typeToName.Add(type, name);
            this.nameToType.Add(name, type);
        }


        public Type Get(string typeName)
        {
            return nameToType[typeName];
        }

        public string Get(Type type)
        {
            return typeToName[type];
        }

        public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
        {
            // we retrieve the name in the RealObjects assembly
            typeName = Get(serializedType);
            assemblyName = "RealObjects";
        }

        public override Type BindToType(string assemblyName, string typeName)
        {
            return Get(typeName);
        }
    } // credit: https://stackoverflow.com/questions/11099466/using-a-custom-type-discriminator-to-tell-json-net-which-type-of-a-class-hierarc

我无法调用构造函数,因为RealObjects.BaseClass没有RealObjects.Tube拥有的Diameter,wallThickness和Length字段,并且在反序列化为RealObjects.BaseClass时我失去了它们的值。 >

// called after being added to the construction queue
private void CreateObject(RealObjects.BaseClass c)
    {
        MyBinder binder = new MyBinder();
        Type type = binder.BindToType("RealObjects", c.Designation); 
        ConstructorInfo[] ctor = type.GetConstructors();
        BasicClass be;
        foreach (ConstructorInfo ci in ctor)
        {
            try
            {
                object instance = ci.Invoke(new object[] { c });
                be = (BasicClass )instance;
            } catch (Exception e)
            {
                Debug.Log(e.ToString());
            }

        }

        // things...

    }

所有建议均已公开

我希望我的英语还不错,并且我已经清楚地解释了自己,谢谢您的帮助

1 个答案:

答案 0 :(得分:1)

难题的缺失部分是序列化方式,该序列化方式缺少“根对象的多态类型信息”,需要如this answer所示将其添加到 Serializing an interface/abstract object using NewtonSoft.JSON 通过dbc

TheoreticalObjects.Tube c = new TheoreticalObjects.Tube(1, "Tube", "Element", 1, 1, "tube", new Length(1, UnitsNet.Units.LengthUnit.Meter), new Length(0.1, UnitsNet.Units.LengthUnit.Meter), new Length(2, UnitsNet.Units.LengthUnit.Meter));
JsonSerializerSettings _jsonSerializerSettingsOCCServer = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto, Formatting = Newtonsoft.Json.Formatting.Indented };
_jsonSerializerSettingsOCCServer.Converters.Add(new UnitsNetJsonConverter());
string json = JsonConvert.SerializeObject(c, typeof(TheoreticalObjects.BaseClass), _jsonSerializerSettingsOCCServer);

反序列化部分的设置与我的第一篇文章相同。 但是活页夹的构造函数会发生变化:

public MyBinder()
{
    List<Type> myTypes = new List<Type>();
    Assembly[] myAssemblies = AppDomain.CurrentDomain.GetAssemblies();
    for (int i = 0; i < myAssemblies.Length; i++)
    {
        if (myAssemblies[i].GetName().Name == "RealObjects")
        {
            foreach (Type t in myAssemblies[i].GetTypes())
            {
                if (t.IsSubclassOf(typeof(RealObjects.BaseClass)))
                {
                    myTypes.Add(t);
                }
            }
            break;
        }
    }

    foreach (var type in myTypes)
    {
        Map(type, "TheoreticalObjects."+type.Name); //this part changed
    }
}

以这种方式绑定到正确的类(RealObjects.Tube)

我的构造队列中有一个RealObjects.Tube类的实例

请注意,我必须将RealObjects.Tube中的字段修改为Length类型,而不是double类型