复杂继承接口的Proto-buf.NET序列化

本文关键字:NET 序列化 Proto-buf 继承 接口 复杂 | 更新日期: 2023-09-27 18:22:35

我想序列化那些实现了几个接口的类,其中一些接口继承自同一个基本接口。目前我使用BinaryFormatter,但我很想使用proto-buf.NET。但我认为目前我将面临类似于上述问题的问题:如何序列化一个类实现两个具有相同接口的接口

我目前想到的唯一可能的解决方案是对我的类进行包装,它序列化了一个更简单的数据类,我用它来创建复杂的类。

让我试着进一步解释它,就像在引用的例子中一样,我有一个这样的结构:

public interface IProduct
{ 
    string SomeMethod(); 
}
public interface ISimpleProduct : IProduct
{ 
    int SomeProperty { get; } 
}
public interface IConstructionProduct : IProduct
{
    int AnotherProperty {get; 
}
public class ConcreteProduct : ISimpleProduct , IConstructionProduct
{
     int SomeProperty {get; set;}
     int AnotherProperty {get; set;}
     string SomeMethod()
     {
           return "A concrete Product";
     }
}

现在我希望序列化ConcreteProduct,因为我认为这在protobuf.net中是不可能的,我正在考虑有一个包装器数据类,比如:

public class ProductData
{
    int[] PropertyValues { get; set;}
}

并在IProductInterface中添加一种构建每个具体产品的方法,如

public interface IProduct
{
      string SomeMethod();
      IProduct BuildProduct(ProductData data);
      ProductData ToData();
}

当然,ProductData在现实中会更复杂,但只是为了概念。我现在要序列化ProductData。我不想更改ProductConcreteProduct类中的接口设置,因为这些接口是以后需要的。我喜欢这种方法的原因是,扩展问题可以在BuildProduct实现中处理。再说一次,我是一个新手,所以如果有什么纯属无稽之谈,请原谅并纠正我。

@Marc,我知道你是作者,这方面的文章很多,但其他帖子(我还没有使用proto-buf)更多,比如DataTable的文章,你关于自动生成列的帖子已经为我节省了很多时间。

复杂继承接口的Proto-buf.NET序列化

这听起来像是在采用联合类型方法。您希望制作一个适合所有产品的单一序列化格式。此外,您希望您的每个产品都映射到该联合类型并映射回。

因此,您仍然关心的是如何进行映射。老实说,从长远来看,我认为您不会对IProduct接口中的这两个方法感到满意。我希望您知道您需要处理反序列化的问题:您实际实例化的是哪种类型?让我这样说:使用您的代码,您必须调用new ConcreteProduct().BuildProduct(data)才能获得您的ConcretePproduct。问题是:你怎么知道它是一个必须实例化的ConcreteProduct?想要调用BuildProduct的代码需要知道这一点!您可以削减这些方法,并为映射任务创建一个单独的基础设施。以下是针对此类问题的工厂方法模式:

public interface IProductMapper {
  IProduct Unmap(ProductData data);
  ProductData Map(IProduct product);
}
public static class ProductMapperFactory {
  public static IProductMapper GetMapper(ProductData data) {
    if (data.Type == "ConcreteProduct") return new ConcreteProductMapper();
    else if ...
  }
  public static IProductMapper GetMapper(IProduct product) {
    if (product is ConcreteProduct) return new ConcreteProductMapper();
    else if ...
  }
}
public class ConcreteProductMapper : IProductMapper {
  public IProduct Unmap(ProductData data) {
    var product = new ConcreteProduct();
    // map properties
    return product;
  }
  public ProductData Map(IProduct data) {
    var data = new ProductData();
    // map data
    return data;
  }
}

你看,关键的一行是data.Type == "ConcreteProduct":不知何故,你必须在数据中指定产品的类型,以便在从联合类型映射回来时知道要实例化哪种产品。

我在联合类型中看到的另一个困难是对象图的反序列化。由于您有自己的序列化类型,因此需要编写自己的代码来分解/组合对象图。如果你像你说的那样是一个新手,那可能会让你陷入一个受伤的世界(或者如果你喜欢的话,也可以是一个学习的世界:-p)。

在任何情况下,它真的需要是您想要反序列化的接口吗?是否可以创建一个类层次结构,从Product基类开始,所有其他产品都从该基类派生,并携带必要的include。我想这会减少麻烦(至少对protobuf来说)。

最后,主要问题是:为什么你想从BinaryFormatter切换到protobuf?