以下代码有什么问题?
MyList l = Serializer.DeepClone(new MyList { "abc" });
Console.WriteLine(l.Count == 1);
其中:
[ProtoContract]
public class MyList : List<String>
{
}
预期:true,actual:false。
答案 0 :(得分:2)
如果您想立即修复,只需带走[ProtoContract]
;列表具有内置行为,不需要标记为合同。
看起来就像在这种情况下,合同定义优先于它是一个列表;我需要仔细查看是否更改这会导致任何不必要的副作用。
工作示例:
public class MyList : List<string>{}
[Test]
public void ListSubclassShouldRoundTrip()
{
var list = new MyList { "abc" };
var clone = Serializer.DeepClone(list);
Assert.AreEqual(1, clone.Count);
Assert.AreEqual("abc", clone[0]);
}
目前破坏的例子:
[ProtoContract]
public class MyContractList : List<string> { }
[Test]
public void ContractListSubclassShouldRoundTrip()
{
var list = new MyContractList { "abc" };
var clone = Serializer.DeepClone(list);
Assert.AreEqual(1, clone.Count);
Assert.AreEqual("abc", clone[0]);
}
更新;但是,看起来这个应该工作,因为当列表是类型的成员时它可以正常工作;只有当列表是图表中的最外层类型时,才会出现此问题。示例(所有测试都通过):
[ProtoContract]
public class ListWrapper
{
[ProtoMember(1)]
public List<string> BasicList { get; set; }
[ProtoMember(2)]
public MyList MyList { get; set; }
[ProtoMember(3)]
public MyContractList MyContractList { get; set; }
}
[Test]
public void TestBasicListAsMember()
{
var obj = new ListWrapper { BasicList = new List<string> { "abc" } };
var clone = Serializer.DeepClone(obj);
Assert.IsNull(clone.MyList);
Assert.IsNull(clone.MyContractList);
Assert.AreEqual(1, clone.BasicList.Count);
Assert.AreEqual("abc", clone.BasicList[0]);
}
[Test]
public void TestMyListAsMember()
{
var obj = new ListWrapper { MyList = new MyList { "abc" } };
var clone = Serializer.DeepClone(obj);
Assert.IsNull(clone.BasicList);
Assert.IsNull(clone.MyContractList);
Assert.AreEqual(1, clone.MyList.Count);
Assert.AreEqual("abc", clone.MyList[0]);
}
[Test]
public void TestMyContractListAsMember()
{
var obj = new ListWrapper { MyContractList = new MyContractList { "abc" } };
var clone = Serializer.DeepClone(obj);
Assert.IsNull(clone.BasicList);
Assert.IsNull(clone.MyList);
Assert.AreEqual(1, clone.MyContractList.Count);
Assert.AreEqual("abc", clone.MyContractList[0]);
}
更新更新:这是一个微妙的错误,由列表可以表现的许多不同方式引起;在列表作为具有getter和setter的成员的情况下,它有一些逻辑说“如果我们得到列表,它不是null,不要调用setter - 只需添加”。但是,处理类型列表的代码意外启用了该模式。所以发生的事情是:它会对数据进行反序列化,然后宣称“你可以放弃这个价值” - 它尽职尽责。然后“永不返回null”代码只会创建一个新列表,而是返回那个。令人讨厌的是,只需要一个单线来修复,没有副作用;在r555修复。
每当有人卡住,我add an integration test; so this shouldn't happen again
答案 1 :(得分:1)
我自己刚刚完成了一个项目,在那里我和Protobut一起工作,在项目中使用了大约30个不同的Protocontracts并且刚刚审查了这个,因为我认为我做的很相似,但实际上我从未直接完成过这个特殊情况。 / p>
所以我只是把它作为测试,但你可以将它用于你的目的。 (是的,它是VB,但我现在更快地敲响VB vs C#[但我到了那里])
结果不是我的预期,所以我在这里发布了我的测试。也许你可以实现Class with Internal列表(暂时让你通过)。
Mylist ProtoBuf False
Mylist BinaryFormatter True
Mylist2 ProtoBuf True
MyListI ProtoBuf False
MyListThing ProtoBuf False
Imports System.IO
Imports ProtoBuf
Public Class Entry
Shared Sub Main()
Dim l As New MyList
l.Add("abc")
Dim newList As MyList
Using ms As New MemoryStream
Serializer.Serialize(Of MyList)(ms, l)
ms.Seek(0, SeekOrigin.Begin)
newList = Serializer.Deserialize(Of MyList)(ms)
End Using
Console.WriteLine("Mylist ProtoBuf {0}", newList.Count = 1)
Dim f As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
Using ms As New MemoryStream
f.Serialize(ms, l)
ms.Seek(0, SeekOrigin.Begin)
newList = CType(f.Deserialize(ms), MyList)
End Using
Console.WriteLine("Mylist BinaryFormatter {0}", newList.Count = 1)
Dim l2 As New MyList2
l2.Items.Add("abc")
Dim newList2 As MyList2
Using ms As New MemoryStream
Serializer.Serialize(Of MyList2)(ms, l2)
ms.Seek(0, SeekOrigin.Begin)
newList2 = Serializer.Deserialize(Of MyList2)(ms)
End Using
Console.WriteLine("Mylist2 ProtoBuf {0}", newList2.Items.Count = 1)
Dim li As New MyListI
li.Add(5)
Dim newListi As MyListI
Using ms As New MemoryStream
Serializer.Serialize(Of MyListI)(ms, li)
ms.Seek(0, SeekOrigin.Begin)
newListi = Serializer.Deserialize(Of MyListI)(ms)
End Using
Console.WriteLine("MyListI ProtoBuf {0}", newListi.Count = 1)
Dim lh As New MyListThing
lh.Add(New Thing() With {.Message = "abc"})
Dim newListh As MyListThing
Using ms As New MemoryStream
Serializer.Serialize(Of MyListThing)(ms, lh)
ms.Seek(0, SeekOrigin.Begin)
newListh = Serializer.Deserialize(Of MyListThing)(ms)
End Using
Console.WriteLine("MyListThing ProtoBuf {0}", newListh.Count = 1)
End Sub
End Class
<ProtoContract(), Serializable()>
Public Class MyList
Inherits List(Of String)
End Class
<ProtoContract()>
Public Class MyList2
Public Sub New()
Items = New List(Of String)
End Sub
<ProtoMember(1)>
Public Property Items As List(Of String)
End Class
<ProtoContract()>
Public Class MyListI
Inherits List(Of Integer)
End Class
<ProtoContract()>
Public Class MyListThing
Inherits List(Of Thing)
End Class
<ProtoContract()>
Public Class Thing
<ProtoMember(1)>
Public Property Message As String
End Class