我得到在我的asmx web服务的WebMethod返回我的对象时,在序列化类型为T 的对象时检测到循环引用。
如果我从T类中删除Equals和GetHashCode问题就消失了。 我没有任何循环引用,所以看起来序列化通过比较对象检测循环引用,如果它们相等则认为有圆圈。
当然,我可以使用Equals定义一个类,并像许多人一样定义另一个类进行序列化,然后将数据从一个复制到另一个类,但我希望能够在一个类中执行它以避免{{3 } parallel class hierarchies之一。
我希望能够定义Equals,GetHashCode并保持code smells。怎么样?
答案 0 :(得分:1)
让我深入了解麻烦的根源。 因为我有同样的问题。
我意识到,问题是在GetHashCode方法中找不到的,而是在Equals方法中找到。
XmlSerializer抛出异常的最重要原因是因为XML文档的结构和"等同机制"在XmlSerializer内部。
例如:
private XmlSerializer serializer;
public void TryToSerialize(TextWriter output)
{
MyObject instance = new MyObject();
instance.Key = 101;
instance.SomeValue = "Some value";
instance.Child = new MyObject();
instance.Child.Key = 101;
instance.Child.SomeValue = "Another value";
serializer.Serialize(output, instance);
}
我是如何实现GetHashCode方法和Equals方法的?
像这样:
public overrides int GetHashCode()
{
return this.Key.GetHashCode();
}
public overrides bool Equals(object obj)
{
if(obj == null) return false;
MyObject other = obj as MyObject;
if(other == null) return false;
return this.Key.Equals(other.Key);
}
如果我运行" TryToSerialize" -method,会发生什么? 我将收到 InvalidOperationException ,并显示消息在序列化类型为T 的对象时检测到循环引用。
在血清化时,XmlSerializer会尝试避免将与子项相同的对象添加到XML文档中,因为这会导致循环。 但检查"的方式是同一个对象"是使用GetHashCode方法和Equals方法来实现它们的目的 - 检查对象的相等性。
在我们的示例中,这些对象migth是不同的实例,并且XmlSerializer不检查内存中的"实例",但使用它知道的方法 - GetHashCode和Equals。
因此,请考虑如何实施 Equals-method
或更好......
考虑如何改进类和方法的实现,以避免在麻烦的根源中出现此问题。 ; - )
答案 1 :(得分:0)
一种方法是从一个接口继承序列化中涉及的每个类,该接口定义OnSerializing方法并在每个类中实现该方法以为符合条件的子级调用它。在每个类中都有Serializing private bool成员,默认为false,并在OnSerializing中将其设置为true。这将允许在root上调用它并传播到所有可序列化节点,直到每个叶子。
在从WebMethod返回可序列化的returnValue之前调用returnValue.OnSerializing()。
每次覆盖等于第一行应为if(Serializing)return base.Equals(obj);
,GetHashCode中的第一行应为if(Serializing)return base.GetHashCode();
通过调用OnSerializing从WebMethod返回之前,就是标记整个树以禁用Equals和GetHashCode的自定义。
如果您需要在序列化后执行某些操作(例如,保存在磁盘上然后返回),则定义OnSerialized并通过树传播,以将Serializing标志设置为false。
当然,如果可能,只需从一个类而不是接口继承所有可序列化对象,并在那里实现所有内容,以减少每个可序列化类中的实现开销。
答案 2 :(得分:0)
就我而言,我解决了正确实现Equals和GetHashCode方法的问题(自动Visual Studio代码补全),如下所示:
import React from 'react';
import {
configure,
shallow
} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import MenuList from './MenuList';
import {
Link
} from 'react-router-dom';
configure({
adapter: new Adapter()
});
const footerItem = {
label: '',
links: [{
label: '',
link: '/'
}]
}
describe('<MenuList />', () => {
let wrapper;
beforeEach(() => {
wrapper = shallow( < MenuList footerItem = {
footerItem
}
/ > );
});
it('should render Link', () => {
console.log(wrapper.props().footerItem); // This should print footerItem object but returning undefined
expect(wrapper.find(Link).length).toBeGreaterThan(0);
});
});
// and here is the code of menulist component/
import React from 'react';
import { Link } from 'react-router-dom';
const menuList = (props) => {
let linkArray=[];
linkArray = props.footerItem.links.map((item,index)=>{
return <li key={index}>
<Link to={item.link}>
{item.label}
</Link></li>
})
return (
<div className="footer-link">
<h6>{props.footerItem.label}</h6>
<ul>
{linkArray}
</ul>
</div>
)
}
export default menuList;
以前的代码只是Equals方法,就像这样:
public override bool Equals(object obj)
{
var permission = obj as Permission;
return permission != null &&
EqualityComparer<AccessLevel>.Default.Equals(Access, permission.Access) &&
EqualityComparer<Functionality>.Default.Equals(Function, permission.Function);
}
public override int GetHashCode()
{
var hashCode = -720887508;
hashCode = hashCode * -1521134295 + EqualityComparer<AccessLevel>.Default.GetHashCode(Access);
hashCode = hashCode * -1521134295 + EqualityComparer<Functionality>.Default.GetHashCode(Function);
return hashCode;
}