JSON。检测到类型的自我引用循环

我尝试序列化从实体数据模型.edmx自动生成的POCO类,当我使用

JsonConvert.SerializeObject

我得到了以下错误:

为System.data.entity类型检测到自我引用循环错误。

我怎么解决这个问题?

453518 次浏览

使用JsonSerializerSettings

  • 如果遇到引用循环,ReferenceLoopHandling.Error(默认)将出错。# EYZ1
  • 如果对象嵌套但不是无限的,ReferenceLoopHandling.Serialize是有用的。
  • 如果一个对象是它自己的子对象,ReferenceLoopHandling.Ignore将不会序列化它。

例子:

JsonConvert.SerializeObject(YourPOCOHere, Formatting.Indented,
new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Serialize
});

如果你必须序列化一个无限嵌套的对象,你可以使用PreserveObjectReferences来避免StackOverflowException。

例子:

JsonConvert.SerializeObject(YourPOCOHere, Formatting.Indented,
new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects
});

选择对要序列化的对象有意义的内容。

参考# EYZ0

最好的解决方案来自Web API中的循环引用处理(这个答案的大部分都是从它复制的):

修复1:全局忽略循环引用

(我已经选择/尝试了这一个,就像其他许多人一样)

json.net序列化器有一个选项可以忽略循环引用。将以下代码放入WebApiConfig.cs文件中:

 config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling
= Newtonsoft.Json.ReferenceLoopHandling.Ignore;

简单的修复将使序列化器忽略引用,这将导致循环。然而,它也有局限性:

  • 数据丢失循环引用信息
  • 该修复只适用于JSON.net
  • 如果有较深的引用链,则无法控制引用的级别

如果你想在非api的ASP中使用这个修复。NET项目,你可以添加上面的行到Global.asax.cs,但首先添加:

var config = GlobalConfiguration.Configuration;

如果你想在net核心项目中使用它,你可以将Startup.cs更改为:

var mvc = services.AddMvc(options =>
{
...
})
.AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);

修复2:全局保存循环引用

第二个修复与第一个类似。只需将代码更改为:

config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling
= Newtonsoft.Json.ReferenceLoopHandling.Serialize;
config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling
= Newtonsoft.Json.PreserveReferencesHandling.Objects;

应用此设置后,数据形状将被更改。

[
{
"$id":"1",
"Category":{
"$id":"2",
"Products":[
{
"$id":"3",
"Category":{
"$ref":"2"
},
"Id":2,
"Name":"Yogurt"
},
{
"$ref":"1"
}
],
"Id":1,
"Name":"Diary"
},
"Id":1,
"Name":"Whole Milk"
},
{
"$ref":"3"
}
]

$id和$ref保留了所有的引用,并使对象图级别平坦,但客户端代码需要知道形状变化才能使用数据,而且它只适用于JSON。NET序列化器。

修复3:忽略并保留引用属性

此修复是在模型类上装饰属性以控制模型或属性级别上的序列化行为。忽略属性:

public class Category
{
public int Id { get; set; }
public string Name { get; set; }
   

[JsonIgnore]
[IgnoreDataMember]
public virtual ICollection<Product> Products { get; set; }
}
JsonIgnore是JSON。而IgnoreDataMember用于XmlDCSerializer。 保留引用:

// Fix 3
[JsonObject(IsReference = true)]
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
  

// Fix 3
//[JsonIgnore]
//[IgnoreDataMember]
public virtual ICollection<Product> Products { get; set; }
}
 

[DataContract(IsReference = true)]
public class Product
{
[Key]
public int Id { get; set; }
 

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

[DataMember]
public virtual Category Category { get; set; }
}

JsonObject(IsReference = true)]是JSON。NET和[DataContract(IsReference = true)]是XmlDCSerializer。注意:在类上应用DataContract后,需要将DataMember添加到想要序列化的属性中。

这些属性可以应用在json和xml序列化器上,并对模型类提供了更多的控制。

修复方法是忽略循环引用,不序列化它们。此行为在JsonSerializerSettings中指定。

单# EYZ0与过载:

JsonConvert.SerializeObject(YourObject, Formatting.Indented,
new JsonSerializerSettings() {
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
}
);

全局设置与代码在Application_Start()在Global.asax.cs:

JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
Formatting = Newtonsoft.Json.Formatting.Indented,
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
};

参考:# EYZ0

您也可以将属性应用到属性。 [JsonProperty( ReferenceLoopHandling = ... )]属性非常适合这个功能

例如:

/// <summary>
/// Represents the exception information of an event
/// </summary>
public class ExceptionInfo
{
// ...code omitted for brevity...


/// <summary>
/// An inner (nested) error.
/// </summary>
[JsonProperty( ReferenceLoopHandling = ReferenceLoopHandling.Ignore, IsReference = true )]
public ExceptionInfo Inner { get; set; }


// ...code omitted for brevity...
}

希望这有帮助, 扬< / p >

最简单的方法是安装Json。网 从nuget中并将[JsonIgnore]属性添加到类中的虚拟属性中,例如
    public string Name { get; set; }
public string Description { get; set; }
public Nullable<int> Project_ID { get; set; }


[JsonIgnore]
public virtual Project Project { get; set; }

尽管这些天,我创建了一个只包含我想要传递的属性的模型,所以它更轻,不包括不需要的集合,并且当我重新构建生成的文件时,我不会丢失我的更改……

要在MVC 6中忽略循环引用并且不全局序列化它们,请在startup.cs中使用以下命令:

    public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().Configure<MvcOptions>(options =>
{
options.OutputFormatters.RemoveTypesOf<JsonOutputFormatter>();
var jsonOutputFormatter = new JsonOutputFormatter();
jsonOutputFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
options.OutputFormatters.Insert(0, jsonOutputFormatter);
});
}

WebApiConfig.cs类中使用这个:

var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);

对我来说,我必须走不同的路线。而不是试图修复JSON。我必须在我的数据上下文的惰性加载之后。

我刚刚添加了这个到我的基本库:

context.Configuration.ProxyCreationEnabled = false;

“context”对象是我在基本存储库中使用的构造函数参数,因为我使用依赖注入。您可以在实例化数据上下文的任何地方更改ProxyCreationEnabled属性。

http://techie-tid-bits.blogspot.com/2015/09/jsonnet-serializer-and-error-self.html

我们可以将这两行添加到DbContext类构造函数中以禁用Self引用循环,例如

public TestContext()
: base("name=TestContext")
{
this.Configuration.LazyLoadingEnabled = false;
this.Configuration.ProxyCreationEnabled = false;
}

在。net Core 1.0中,你可以在Startup.cs文件中设置全局设置:

using System.Buffers;
using Microsoft.AspNetCore.Mvc.Formatters;
using Newtonsoft.Json;


// beginning of Startup class


public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.OutputFormatters.Clear();
options.OutputFormatters.Add(new JsonOutputFormatter(new JsonSerializerSettings(){
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
}, ArrayPool<char>.Shared));
});
}

简单地将Configuration.ProxyCreationEnabled = false;放在上下文文件中;这样问题就解决了。

public demEntities()
: base("name=demEntities")
{
Configuration.ProxyCreationEnabled = false;
}

我喜欢从Application_Start()开始的解决方案,因为答案是在这里

显然,我无法在JavaScript中使用我的函数中的配置访问json对象,因为在DalSoft的答案中,对象返回有"\n \r"遍历对象的(key, val)。

不管怎样,只要能工作就好(因为不同的方法在不同的场景下工作,这取决于所提出的意见和问题),尽管最好采用一种标准的方法,并提供一些良好的文档支持该方法。

当你有循环问题时,序列化使用NEWTONSOFTJSON,在我的情况下,我不需要修改全局。野蔷薇或野蔷薇。我只是使用JsonSerializesSettings忽略循环处理。

JsonSerializerSettings jss = new JsonSerializerSettings();
jss.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
var lst = db.shCards.Where(m => m.CardID == id).ToList();
string json = JsonConvert.SerializeObject(lst, jss);

我有这个例外,我的工作解决方案很简单,

通过添加JsonIgnore属性来忽略引用属性:

[JsonIgnore]
public MyClass currentClass { get; set; }

反序列化时重置属性:

Source = JsonConvert.DeserializeObject<MyObject>(JsonTxt);
foreach (var item in Source)
{
Source.MyClass = item;
}

使用Newtonsoft.Json;

如果你使用的是。net Core 2。在Startup.cs中更新ConfigureServices部分

https://learn.microsoft.com/en-us/ef/core/querying/related-data/serialization

    public void ConfigureServices(IServiceCollection services)
{
...


services.AddMvc()
.AddJsonOptions(options =>
options.SerializerSettings.ReferenceLoopHandling =
Newtonsoft.Json.ReferenceLoopHandling.Ignore
);


...
}

如果你使用的是。net Core 3。x - 5.0,没有MVC,它将是:

# startup.cs
services.AddControllers()
.AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling =
Newtonsoft.Json.ReferenceLoopHandling.Ignore
);

对于。net 6.0,唯一的不同是它现在在Program.cs中。

# program.cs
services.AddControllers()
.AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling =
Newtonsoft.Json.ReferenceLoopHandling.Ignore);

如果你使用实体框架和数据库优先的设计模式,这个引用循环处理几乎是强制性的。

对于不循环这为我工作-
# EYZ0 < / p > 我已经在这里解决了所有问题-实体框架子序列化与.Net Core 2 WebAPI # EYZ0 < / p >

将感谢任何评论。 也许有人可以在某个时候使用它。

人们已经讨论过将[JsonIgnore]添加到类中的虚拟属性,例如:

[JsonIgnore]
public virtual Project Project { get; set; }

我还将分享另一个选项,[JsonProperty(NullValueHandling = NullValueHandling. ignore)],仅当它为空时才从序列化中省略该属性:

[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public virtual Project Project { get; set; }

团队:

这适用于ASP。核心网;上面的挑战是如何“设置为忽略”。根据您设置应用程序的方式,这可能相当具有挑战性。以下是对我有效的方法。

这可以放在你的公共void ConfigureServices(IServiceCollection services)部分。

services.AddMvc().AddJsonOptions(opt =>
{
opt.SerializerSettings.ReferenceLoopHandling =
Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});

我的问题解决了自定义配置JsonSerializerSettings:

services.AddMvc(
// ...
).AddJsonOptions(opt =>
{
opt.SerializerSettings.ReferenceLoopHandling =
Newtonsoft.Json.ReferenceLoopHandling.Serialize;
opt.SerializerSettings.PreserveReferencesHandling =
Newtonsoft.Json.PreserveReferencesHandling.Objects;
});

对于. net Core 3.0,更新Startup.cs类,如下所示。

public void ConfigureServices(IServiceCollection services)
{
...


services.AddControllers()
.AddNewtonsoftJson(
options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);


...
}

看到:# EYZ0

请确保在您的方法中使用await和async。如果对象没有正确序列化,就会出现此错误。

我也面临着同样的问题,我尝试使用JsonSetting来忽略自引用错误,它的某种工作,直到我得到一个类,自引用非常深入,我的。net进程挂在Json写入值。

我的问题

    public partial class Company : BaseModel
{
public Company()
{
CompanyUsers = new HashSet<CompanyUser>();
}


public string Name { get; set; }


public virtual ICollection<CompanyUser> CompanyUsers { get; set; }
}


public partial class CompanyUser
{
public int Id { get; set; }
public int CompanyId { get; set; }
public int UserId { get; set; }


public virtual Company Company { get; set; }


public virtual User User { get; set; }
}


public partial class User : BaseModel
{
public User()
{
CompanyUsers = new HashSet<CompanyUser>();
}


public string DisplayName { get; set; }
public virtual ICollection<CompanyUser> CompanyUsers { get; set; }


}

你可以在User类中看到问题,它引用了CompanyUser类,这是一个自引用。

现在,我正在调用包含所有关系属性的GetAll方法。

cs.GetAll("CompanyUsers", "CompanyUsers.User");

在这个阶段,我的DotNetCore进程挂在执行JsonResult,写入值…上,从来没有来过。在Startup.cs中,我已经设置了JsonOption。出于某种原因,EFCore包含了嵌套属性,我没有要求Ef给出。

    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

预期的行为应该是这样的

嘿,EfCore,你能把“CompanyUsers”数据也包括在我的 公司类,以便我可以轻松访问数据。

然后

嘿,EfCore,你能把“CompanyUsers。用户”数据作为 这样我就可以像这样轻松地访问数据 Company.CompanyUsers.First () .User.DisplayName < / >强

在这个阶段,我应该只得到这个“Company.CompanyUsers.First () .User.DisplayName”,它不应该给我.User.CompanyUsers Company.CompanyUsers.First (),导致自引用问题;从技术上讲,它不应该给我用户。CompanyUsers作为CompanyUsers是一个导航属性。但是,EfCore非常兴奋,给了我用户。CompanyUsers

所以,我决定为属性写一个扩展方法来排除对象(它实际上不是排除它只是设置属性为null)。不仅如此,它还适用于数组属性。下面是我还将为其他用户导出nuget包的代码(不确定这是否甚至有助于某人)。原因很简单,因为我懒得写.Select(n => new {n.p1, n.p2});,我只是不想写选择语句只排除1个属性!

这不是最好的代码(我会在某个阶段更新),因为我写得很匆忙,尽管这可能会帮助那些想要排除(设置null)对象数组的人。

    public static class PropertyExtensions
{
public static void Exclude<T>(this T obj, Expression<Func<T, object>> expression)
{
var visitor = new PropertyVisitor<T>();
visitor.Visit(expression.Body);
visitor.Path.Reverse();
List<MemberInfo> paths = visitor.Path;
Action<List<MemberInfo>, object> act = null;


int recursiveLevel = 0;
act = (List<MemberInfo> vPath, object vObj) =>
{


// set last propert to null thats what we want to avoid the self-referencing error.
if (recursiveLevel == vPath.Count - 1)
{
if (vObj == null) throw new ArgumentNullException("Object cannot be null");


vObj.GetType().GetMethod($"set_{vPath.ElementAt(recursiveLevel).Name}").Invoke(vObj, new object[] { null });
return;
}


var pi = vObj.GetType().GetProperty(vPath.ElementAt(recursiveLevel).Name);
if (pi == null) return;
var pv = pi.GetValue(vObj, null);
if (pi.PropertyType.IsArray || pi.PropertyType.Name.Contains("HashSet`1") || pi.PropertyType.Name.Contains("ICollection`1"))
{
var ele = (IEnumerator)pv.GetType().GetMethod("GetEnumerator").Invoke(pv, null);


while (ele.MoveNext())
{
recursiveLevel++;
var arrItem = ele.Current;


act(vPath, arrItem);


recursiveLevel--;
}


if (recursiveLevel != 0) recursiveLevel--;
return;
}
else
{
recursiveLevel++;
act(vPath, pv);
}


if (recursiveLevel != 0) recursiveLevel--;


};


// check if the root level propert is array
if (obj.GetType().IsArray)
{
var ele = (IEnumerator)obj.GetType().GetMethod("GetEnumerator").Invoke(obj, null);
while (ele.MoveNext())
{
recursiveLevel = 0;
var arrItem = ele.Current;


act(paths, arrItem);
}
}
else
{
recursiveLevel = 0;
act(paths, obj);
}


}


public static T Explode<T>(this T[] obj)
{
return obj.FirstOrDefault();
}


public static T Explode<T>(this ICollection<T> obj)
{
return obj.FirstOrDefault();
}
}

上面的扩展类将使您能够将属性设置为null,以避免自引用循环甚至数组。

表达式构建器

    internal class PropertyVisitor<T> : ExpressionVisitor
{
public readonly List<MemberInfo> Path = new List<MemberInfo>();


public Expression Modify(Expression expression)
{
return Visit(expression);
}




protected override Expression VisitMember(MemberExpression node)
{
if (!(node.Member is PropertyInfo))
{
throw new ArgumentException("The path can only contain properties", nameof(node));
}


Path.Add(node.Member);
return  base.VisitMember(node);
}
}

用法:

模型类

    public class Person
{
public string Name { get; set; }
public Address AddressDetail { get; set; }
}


public class Address
{
public string Street { get; set; }
public Country CountryDetail { get; set; }
public Country[] CountryDetail2 { get; set; }
}


public class Country
{
public string CountryName { get; set; }
public Person[] CountryDetail { get; set; }
}

虚拟数据

           var p = new Person
{
Name = "Adeel Rizvi",
AddressDetail = new Address
{
Street = "Sydney",
CountryDetail = new Country
{
CountryName = "AU"
}
}
};


var p1 = new Person
{
Name = "Adeel Rizvi",
AddressDetail = new Address
{
Street = "Sydney",
CountryDetail2 = new Country[]
{
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A1" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A2" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A3" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A4" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A5" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A6" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A7" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A8" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A9" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A1" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A2" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A3" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A4" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A5" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A6" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A7" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A8" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A9" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },


}
}
};

例:

情况1:只排除没有任何数组的属性

p.Exclude(n => n.AddressDetail.CountryDetail.CountryName);

案例2:排除带有1个数组的属性

p1.Exclude(n => n.AddressDetail.CountryDetail2.Explode().CountryName);

案例3:排除带有2个嵌套数组的属性

p1.Exclude(n => n.AddressDetail.CountryDetail2.Explode().CountryDetail.Explode().Name);

案例4:包含EF GetAll查询

var query = cs.GetAll("CompanyUsers", "CompanyUsers.User").ToArray();
query.Exclude(n => n.Explode().CompanyUsers.Explode().User.CompanyUsers);
return query;

你已经注意到,爆炸()方法也是一个扩展方法,用于我们的表达式构建器从数组属性中获取属性。只要有数组属性,就使用.Explode()。YourPropertyToExclude或. explosion (). property1 . myarrayproperty . explosion ().MyStupidProperty。上面的代码帮助我避免像我想要的那样深的自我引用。现在我可以使用GetAll并排除我不想要的属性!

感谢你阅读这篇文章!

c#代码:

            var jsonSerializerSettings = new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
};


var jsonString = JsonConvert.SerializeObject(object2Serialize, jsonSerializerSettings);


var filePath = @"E:\json.json";


File.WriteAllText(filePath, jsonString);

我继承了一个数据库应用程序,为web页面提供数据模型。默认情况下,序列化将尝试遍历整个模型树,这里的大多数答案都是如何防止这种情况的良好开端。

一个尚未探索的选项是使用接口来提供帮助。我将从之前的例子中窃取:

public partial class CompanyUser
{
public int Id { get; set; }
public int CompanyId { get; set; }
public int UserId { get; set; }


public virtual Company Company { get; set; }


public virtual User User { get; set; }
}


public interface IgnoreUser
{
[JsonIgnore]
User User { get; set; }
}


public interface IgnoreCompany
{
[JsonIgnore]
User User { get; set; }
}


public partial class CompanyUser : IgnoreUser, IgnoreCompany
{
}

在上述解决方案中,没有Json设置受到损害。将LazyLoadingEnabled和或ProxyCreationEnabled设置为false会影响所有的后端编码,并阻止ORM工具的一些真正好处。LazyLoading/ProxyCreation设置可以在不手动加载的情况下阻止导航属性的加载,这取决于您的应用程序。

这里有一个更好的解决方案,以防止导航属性序列化,它使用标准的json功能: # EYZ0 < / p >

只需更新Startup.cs文件中的services.AddControllers ()即可

services.AddControllers()
.AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);

在。net 5中。x,用下面的代码更新startup.cs中的ConfigureServices方法

public void ConfigureServices(IServiceCollection services)
{
----------------
----------------
services.AddMvc().AddJsonOptions(options =>
{
options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve;
});
------------------
}
默认情况下,序列化(System.Text.Json.Serialization)不支持带周期的对象,也不保留重复引用。使用保存在序列化时启用唯一对象引用保存,并在反序列化时使用元数据读取保存的引用。 # EYZ0 < / p >