Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/283.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在一个程序集中序列化,在另一个程序集中反序列化?_C#_Serialization_Json.net_Protobuf Net_Binaryformatter - Fatal编程技术网

C# 在一个程序集中序列化,在另一个程序集中反序列化?

C# 在一个程序集中序列化,在另一个程序集中反序列化?,c#,serialization,json.net,protobuf-net,binaryformatter,C#,Serialization,Json.net,Protobuf Net,Binaryformatter,我在两个项目中使用了相同的类,一个在运行时上发送给另一个进程,该进程必须反序列化该对象并使用它(假定两个对象是相同的,但程序集名称不同,因此它们实际上被解释为两种不同的类型)。根据我的研究,我提出了一些不可行的解决方案,原因如下 Json.NET:给出两种类型不兼容的例外情况(尝试在序列化设置中使用typename.all) protobuf-net:要求我在任何地方添加属性,或者只为其提供属性名称(在v2中),由于我的对象太复杂,这两种方法对我来说都是不可能的 BinaryFormatter:

我在两个项目中使用了相同的类,一个在
运行时
上发送给另一个进程,该进程必须反序列化该对象并使用它(假定两个对象是相同的,但程序集名称不同,因此它们实际上被解释为两种不同的类型)。根据我的研究,我提出了一些不可行的解决方案,原因如下

Json.NET
:给出两种类型不兼容的例外情况(尝试在序列化设置中使用typename.all)

protobuf-net
:要求我在任何地方添加属性,或者只为其提供属性名称(在v2中),由于我的对象太复杂,这两种方法对我来说都是不可能的

BinaryFormatter
:与protobuf相同的原因->大量属性

使用公共程序集
:由于一些与我的项目架构相关的原因,我不能


那么,有没有简单的方法将一个类型序列化,然后将其反序列化为另一个类型(实际上是同一个类,但在不同的程序集中)

是的,完全可以使用一个程序集中的类进行序列化,并使用Json.Net反序列化为另一个程序集中的类。事实上,这首先是序列化的主要用例之一——在不同系统之间传输数据

您需要记住两件事:

  • 如果源程序集和目标程序集不同,则不应将实际的完全限定类型名作为元数据包含在JSON中。换句话说,请确保
    typenameholling
    设置设置为
    None
    (我认为这是默认设置)。如果包含类型名元数据,那么Json.Net将期望在接收端找到这些程序集,而反序列化将失败,因为这些程序集不在那里
  • 如果在类结构中使用接口而不是具体类型,则需要创建一个或多个
    JsonConverter
    类来处理反序列化。当Json.Net看到一个接口时,它不知道要创建什么类型的具体类,因为它可以是任何类型。转换器可以查找JSON中可能存在的其他数据,并告诉JSON.Net实例化哪个具体类。如果JSON中没有明显的数据段可用作类型的指示符,则可以使用序列化端的转换器添加自定义指示符
  • 下面是一些示例代码来演示我列出的概念。演示分为两部分。第一部分是“sender”,它将一个虚构的“diagram”类结构序列化为JSON并将其写入一个文件。第二部分是“接收者”,它读取文件并将JSON反序列化为一组不同的类。您会注意到,我有意使接收方中的一些类名与发送方不同,但它们具有相同的属性名和结构,因此仍然有效。您还将注意到,receiver程序使用一个自定义的
    JsonConverter
    来处理创建正确的
    IFigure
    实例,使用JSON中的某些属性作为指示符

    发件人 接受者
    两个程序集是否都可以引用一个公共程序集?我唯一能想到的另一件事是在不使用任何名称空间的情况下使用XML。到目前为止,最好的解决方案是使用一个公共库。@DanielEugen为什么程序集信息会被序列化?序列化的结果应该可以完全转移到另一个运行时或语言。它不应该关心源程序集元数据。@DanielEugen,在使用JSON.NET时,请尝试
    TypeNameHandling.None
    而不是
    TypeNameHandling.All
    All
    值告诉序列化程序包含所有对象的类型信息,该类型信息可能是导致不兼容错误的原因。将其设置为
    None
    将排除所有类型信息。您可以检查序列化对象中的$type属性,以验证是否包含类型信息。@在Json.NET中,我试图为反序列化程序提供
    TypeNameAssemblyStyle=FormatterAssemblyStyle.Simple
    设置,该设置本应忽略程序集名称的更改,但我仍然获得中指定的类型JSON与异常不兼容。
    using System.Collections.Generic;
    using System.IO;
    using Newtonsoft.Json;
    
    namespace Sender
    {
        class Program
        {
            static void Main(string[] args)
            {
                Diagram diagram = new Diagram
                {
                    Title = "Flowchart",
                    Shapes = new List<IShape>
                    {
                        new Circle 
                        { 
                            Id = 1, 
                            Text = "Foo", 
                            Center = new Point { X = 1, Y = 5 }, 
                            Radius = 1.25 
                        },
                        new Line 
                        {
                            Id = 2,
                            A = new Point { X = 2.25, Y = 5 }, 
                            B = new Point { X = 4, Y = 5 } 
                        },
                        new Rectangle
                        {
                            Id = 3,
                            Text = "Bar",
                            TopLeft = new Point { X = 4, Y = 6.5 }, 
                            BottomRight = new Point { X = 8.5, Y = 3.5 } 
                        }
                    }
                };
    
                string json = JsonConvert.SerializeObject(diagram, Formatting.Indented);
    
                File.WriteAllText(@"C:\temp\test.json", json);
            }
        }
    
        class Diagram
        {
            public string Title { get; set; }
            public List<IShape> Shapes { get; set; }
        }
    
        interface IShape
        {
            int Id { get; set; }
            string Text { get; set; }
        }
    
        abstract class AbstractShape : IShape
        {
            public int Id { get; set; }
            public string Text { get; set; }
        }
    
        class Line : AbstractShape
        {
            public Point A { get; set; }
            public Point B { get; set; }
        }
    
        class Rectangle : AbstractShape
        {
            public Point TopLeft { get; set; }
            public Point BottomRight { get; set; }
        }
    
        class Circle : AbstractShape
        {
            public Point Center { get; set; }
            public double Radius { get; set; }
        }
    
        class Point
        {
            public double X { get; set; }
            public double Y { get; set; }
        }
    }
    
    {
      "Title": "Flowchart",
      "Shapes": [
        {
          "Center": {
            "X": 1.0,
            "Y": 5.0
          },
          "Radius": 1.25,
          "Id": 1,
          "Text": "Foo"
        },
        {
          "A": {
            "X": 2.25,
            "Y": 5.0
          },
          "B": {
            "X": 4.0,
            "Y": 5.0
          },
          "Id": 2,
          "Text": null
        },
        {
          "TopLeft": {
            "X": 4.0,
            "Y": 6.5
          },
          "BottomRight": {
            "X": 8.5,
            "Y": 3.5
          },
          "Id": 3,
          "Text": "Bar"
        }
      ]
    }
    
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    
    namespace Receiver
    {
        class Program
        {
            static void Main(string[] args)
            {
                string json = File.ReadAllText(@"C:\temp\test.json");
    
                JsonSerializerSettings settings = new JsonSerializerSettings();
                settings.Converters.Add(new FigureConverter());
    
                Chart chart = JsonConvert.DeserializeObject<Chart>(json, settings);
    
                Console.WriteLine(chart);
                Console.ReadKey();
            }
        }
    
        class FigureConverter : JsonConverter
        {
            public override bool CanConvert(Type objectType)
            {
                return (objectType == typeof(IFigure));
            }
    
            public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
            {
                JObject jo = JObject.Load(reader);
                if (jo["Center"] != null)
                {
                    return jo.ToObject<Circle>(serializer);
                }
                else if (jo["TopLeft"] != null)
                {
                    return jo.ToObject<Rectangle>(serializer);
                }
                else
                {
                    return jo.ToObject<Line>(serializer);
                }
            }
    
            public override bool CanWrite
            {
                get { return false; }
            }
    
            public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
            {
                throw new NotImplementedException();
            }
        }
    
        class Chart
        {
            public string Title { get; set; }
            public List<IFigure> Shapes { get; set; }
    
            public override string ToString()
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("Chart: ");
                sb.AppendLine(Title);
                foreach (IFigure figure in Shapes)
                {
                    sb.AppendLine(figure.ToString());
                }
                return sb.ToString();
            }
        }
    
        interface IFigure
        {
            int Id { get; set; }
            string Text { get; set; }
        }
    
        abstract class AbstractFigure : IFigure
        {
            public int Id { get; set; }
            public string Text { get; set; }
        }
    
        class Line : AbstractFigure
        {
            public Point A { get; set; }
            public Point B { get; set; }
            public override string ToString()
            {
                return string.Format("Line: A = {0}, B = {1}", A, B);
            }
        }
    
        class Rectangle : AbstractFigure
        {
            public Point TopLeft { get; set; }
            public Point BottomRight { get; set; }
            public override string ToString()
            {
                return string.Format("Rectangle: TopLeft = {0}, BottomRight = {1}", TopLeft, BottomRight);
            }
        }
    
        class Circle : AbstractFigure
        {
            public Point Center { get; set; }
            public double Radius { get; set; }
            public override string ToString()
            {
                return string.Format("Circle: Center = {0}, Radius = {1}", Center, Radius);
            }
        }
    
        class Point
        {
            public double X { get; set; }
            public double Y { get; set; }
            public override string ToString()
            {
                return string.Format("({0:0.##}, {1:0.##})", X, Y);
            }
        }
    }
    
    Chart: Flowchart
    Circle: Center = (1, 5), Radius = 1.25
    Line: A = (2.25, 5), B = (4, 5)
    Rectangle: TopLeft = (4, 6.5), BottomRight = (8.5, 3.5)