没有标注protobuf网系列化 [英] Protobuf-net serialization without annotation

查看:308
本文介绍了没有标注protobuf网系列化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看了<一个href=\"http://stackoverflow.com/questions/8175030/is-datamemberorder-n-annotation-required-for-protobuf-net-v2\">this回答和我在一个情况下,我并不需要保持向后兼容,我必须有一个无需装饰几十所需要的protobuf网的属性类的解决方案。所以我试图用 RuntimeTypeModel.Default.InferTagFromNameDefault = TRUE; 但我可能是无法正确使用它,因为Serializer.Serialize通话仍然会抛出一个异常,要求合同。下面是我简单的测试,我究竟做错了什么?

 公开枚举CompanyTypes
{
    无,小,大,企业启动
}公共类BaseUser
{
    公共字符串SSN {搞定;组; }
}公共类用户:BaseUser
{
    公共字符串名字{获得;组; }
    公共字符串名字{获得;组; }
    公众诠释年龄{搞定;组; }
    公众的DateTime出生日期{搞定;组; }
    公开名单&LT;串GT;朋友{搞定;组; }
    公众公司的公司{搞定;组; }
}公共类公司
{
    公共字符串名称{;组; }
    公共字符串地址{搞定;组; }
    公共CompanyTypes类型{搞定;组; }
    公开名单&LT;产品与GT;产品{搞定;组; }
}公共类产品
{
    公共字符串名称{;组; }
    公共字符串SKU {搞定;组; }
}[识别TestClass]
公共类SerializationTest
{
    [测试方法]
    公共无效SerializeDeserializeTest()
    {
        VAR用户=新用户
                       {
                           年龄= 10,
                           出生日期= DateTime.Now.AddYears(-10),
                           名字=测试第一
                           姓氏=测试最后
                           朋友=新的List&LT;串GT; {鲍勃,约翰},
                           公司=新公司
                                         {
                                             NAME =测试公司
                                             地址=廷巴克图
                                             类型= CompanyTypes.Startup,
                                             产品=新的List&LT;产品与GT;
                                             {
                                                新产品{名称=Nerf了火箭,SKU =12324AC},
                                                新产品{名称=的Nerf飞镖,SKU =DHSN123}
                                             }
                                         }
                       };        RuntimeTypeModel.Default.InferTagFromNameDefault = TRUE;
        使用(VAR的MemoryStream =新的MemoryStream())
        {
            Serializer.Serialize(MemoryStream的,用户);
            变种序列= Convert.ToBase64String(memoryStream.GetBuffer(),0,(int)的memoryStream.Length);
        }
    }
}


解决方案

InferTagFromName (和它的孪生兄弟 InferTagFromNameDefault )只需要一个手时,有必要解决的标签号的一个成员;它们不影响该部件需要被序列化(因此目前这个问题的答案是:无,即使系统知道它们)。您的的选项可能的选择将是 ImplicitFields ,但是这是目前仅可作为一个 [ProtoContract(... )] 标记。如果你不介意的的注释,以务实的修复可能是:

  [ProtoContract(ImplicitFields = ImplicitFields.AllPublic)

用户公司产品,和一些更复杂一点的 BaseUser (因继承):

  [ProtoContract(ImplicitFields = ImplicitFields.AllPublic,ImplicitFirstTag = 10)]
[ProtoInclude(1的typeof(用户))]

请注意,我们还没有添加大量的每个成员的注释。如果你是真的真的防属性,那么它也可以通过配置code整个模型,通过:

  RuntimeTypeModel.Default.Add(typeof运算(产品),假的)。新增(姓名,SKU);
RuntimeTypeModel.Default.Add(typeof运算(公司),假的)。新增(姓名,地​​址,
         类型,产品);
RuntimeTypeModel.Default.Add(typeof运算(用户),假的)。新增(名字,姓氏,
         时代,出生日期,朋友,本公司);
RuntimeTypeModel.Default.Add(typeof运算(BaseUser),假的)。新增(10,SSN)
         .AddSubType(1的typeof(用户));

I looked at this answer and I am in a situation where I don't need to maintain backward compatibility and I have to have a solution that works without having to decorate dozens of classes with the attributes needed for protobuf-net. So I tried using RuntimeTypeModel.Default.InferTagFromNameDefault = true; but I may be not using it correctly because the Serializer.Serialize call still throws an exception asking for a contract. Here is my quick test, what am I doing wrong?

public enum CompanyTypes
{
    None, Small, Big, Enterprise, Startup
}

public class BaseUser
{
    public string SSN { get; set; }    
}

public class User : BaseUser
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
    public DateTime BirthDate { get; set; }
    public List<string> Friends { get; set; }
    public Company Company { get; set; }
}

public class Company
{
    public string Name { get; set; }
    public string Address { get; set; }
    public CompanyTypes Type { get; set; }
    public List<Product> Products { get; set; }
}

public class Product
{
    public string Name { get; set; }
    public string Sku { get; set; }
}

[TestClass]
public class SerializationTest
{
    [TestMethod]
    public void SerializeDeserializeTest()
    {
        var user = new User
                       {
                           Age = 10,
                           BirthDate = DateTime.Now.AddYears(-10),
                           FirstName = "Test First",
                           LastName = "Test Last",
                           Friends = new List<string> { "Bob", "John" },
                           Company = new Company
                                         {
                                             Name = "Test Company",
                                             Address = "Timbuktu",
                                             Type = CompanyTypes.Startup,
                                             Products = new List<Product>
                                             {
                                                new Product{Name="Nerf Rocket", Sku="12324AC"},
                                                new Product{Name="Nerf Dart", Sku="DHSN123"}
                                             }
                                         }
                       };

        RuntimeTypeModel.Default.InferTagFromNameDefault = true;
        using (var memoryStream = new MemoryStream())
        {
            Serializer.Serialize(memoryStream, user);
            var serialized = Convert.ToBase64String(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
        }
    }
}

解决方案

InferTagFromName (and it's twin, InferTagFromNameDefault) only take a hand when it is necessary to resolve a tag number for a member; they don't influence which members need to be serialized (so currently the answer to that would be: none, even if the system knew about them). The option you might have chosen would be ImplicitFields, but that is currently only available as a [ProtoContract(...)] marker. If you don't mind a little annotation, a pragmatic fix may be:

[ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]

on User, Company and Product, and something a bit more complex for BaseUser (because of the inheritance):

[ProtoContract(ImplicitFields = ImplicitFields.AllPublic, ImplicitFirstTag = 10)]
[ProtoInclude(1, typeof(User))]

Note we haven't had to add lots of per-member annotation. If you are really really anti-attributes, then it is also possible to configure the entire model through code, via:

RuntimeTypeModel.Default.Add(typeof(Product), false).Add("Name", "Sku");
RuntimeTypeModel.Default.Add(typeof(Company), false).Add("Name", "Address",
         "Type", "Products");
RuntimeTypeModel.Default.Add(typeof(User), false).Add("FirstName", "LastName",
         "Age", "BirthDate", "Friends", "Company");
RuntimeTypeModel.Default.Add(typeof(BaseUser), false).Add(10, "SSN")
         .AddSubType(1, typeof(User));

这篇关于没有标注protobuf网系列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆