c# - List 的 Protocol buffer 序列化

标签 c# .net protobuf-net

下面的代码有什么问题?

MyList l = Serializer.DeepClone(new MyList { "abc" });
Console.WriteLine(l.Count == 1);

地点:

[ProtoContract]
public class MyList : List<String>
{
}

预期:真,实际:假。

最佳答案

如果你想立即修复,只需拿走[ProtoContract];列表具有内置行为,不需要标记为契约。

在这种情况下,看起来契约(Contract)定义优先于它是一个列表的事实;我需要仔细查看更改此设置是否会导致任何不需要的副作用。

工作示例:

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 的成员的情况下,它有一些逻辑说“如果我们得到列表,并且它不为空,请不要调用 setter - 只需添加”。但是,处理类型列表的代码意外启用了该模式。所以发生的事情是:它会反序列化数据,然后宣称“你可以丢弃这个值”——它尽职尽责地做了。然后“永不返回 null”代码只会创建一个新列表,并返回 that。令人烦恼的是,只需修复一条线,而且没有副作用;固定在 r555 中。

每当有人卡住时,我 add an integration test; so this shouldn't happen again

关于c# - List 的 Protocol buffer 序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11656439/

相关文章:

c# - 如何使用 Unity 注册 AutoMapper 配置文件

c# - ASP.NET 应用程序对象 getter 和 setter

c# - 如何使 protobuf-net 在反序列化时不考虑默认数组值

protobuf-net - 我可以使用 protobuf-net 序列化任意类型吗?

c# - 具有 Protobuf 格式的 ServiceStack

c# - 如何使用按位&(和)来实现这个?

c# - WPF 自定义控件 : DependencyProperty of Collection type

c# - 如何将此 HipChat curl 帖子转换为 C#?

c# - 是否可以获取当前事件应用程序的名称

.net - 什么时候使用 Tuple 和 KeyValuePair 更好?