protobuf-net 代理的这种用法有什么问题?

发布于 2024-11-09 02:31:12 字数 3633 浏览 0 评论 0原文

使用 protobuf-net v2 观察这个简单的代码:

  interface IObject { }

  [ProtoContract]
  class Person : IObject
  {
    [ProtoMember(1)]
    public int Id { get; set; }
    [ProtoMember(2)]
    public string Name { get; set; }
    [ProtoMember(3, AsReference = true)]
    public Address Address { get; set; }
  }
  [ProtoContract]
  class Address : IObject
  {
    [ProtoMember(1)]
    public string Line1 { get; set; }
    [ProtoMember(2)]
    public string Line2 { get; set; }
  }

  class Command
  {
    public List<IObject> Objects { get; set; }
  }

  internal interface ICommandSurrogatePiece
  {
    IEnumerable<IObject> Objects { get; set; }
  }

  [ProtoContract]
  class CommandSurrogatePiece<T> : ICommandSurrogatePiece 
      where T : class, IObject
  {
    [ProtoMember(1)]
    public List<T> Objects { get; set; }

    #region ICommandSurrogatePiece Members

    IEnumerable<IObject> ICommandSurrogatePiece.Objects
    {
      get { return Objects; }
      set { Objects = value as List<T> ?? value.Cast<T>().ToList(); }
    }

    #endregion
  }

  [ProtoContract]
  class CommandSurrogate
  {
    public static implicit operator Command(CommandSurrogate surrogate)
    {
      var objects = surrogate.Pieces.SelectMany(c => c.Objects).ToList();
      return new Command { Objects = objects };
    }
    public static implicit operator CommandSurrogate(Command cmd)
    {
      var pieces = cmd.Objects.GroupBy(o => o.GetType(), 
          o => o, CreateCommandSurrogatePiece).ToList();
      return new CommandSurrogate { Pieces = pieces };
    }

    private static ICommandSurrogatePiece CreateCommandSurrogatePiece(
        Type type, IEnumerable<IObject> objects)
    {
      var piece = (ICommandSurrogatePiece)Activator.CreateInstance(
          typeof(CommandSurrogatePiece<>).MakeGenericType(type));
      piece.Objects = objects;
      return piece;
    }

    [ProtoMember(1, DynamicType = true)]
    public List<ICommandSurrogatePiece> Pieces { get; set; }
  }

  class Program
  {
    static void Main()
    {
      var person = new Person { Id = 12345, Name = "Fred", Address = 
          new Address { Line1 = "Flat 1", Line2 = "The Meadows" } };
      var person2 = new Person { Id = 2345, Name = "Fred kaka", Address = 
          new Address { Line1 = "Flat 12", Line2 = "The Meadows kuku" } };
      var address = 
          new Address { Line1 = "Flat 2", Line2 = "The Meadows Double" };
      var address2 = 
          new Address { Line1 = "Flat 2 bubub", 
              Line2 = "The Meadows Double kuku" };

      var model = TypeModel.Create();
      model.Add(typeof(CommandSurrogate), true);
      model.Add(typeof(Command), false).SetSurrogate(typeof(CommandSurrogate));
      var command = new Command { Objects = 
          new List<IObject> { person, address, person2, address2 } };
      var command2 = (Command)(CommandSurrogate)command;
      var command3 = Serializer.DeepClone(command);
    }
  }

最后一行失败并出现异常。我做错了什么? 谢谢。

编辑

System.InvalidOperationException occurred
  Message=Type is not expected, and no contract can be inferred: HelloProtoBuf.Command
  Source=protobuf-net
  StackTrace:
       at ProtoBuf.Meta.TypeModel.ThrowUnexpectedType(Type type)
  InnerException: 

编辑2

我稍微修改了代码以修复代理代码,但这不会影响问题 - 它仍然存在。

EDIT3

我知道 command2command 包含不同顺序的对象。这在我的场景中是可以接受的。我原本期望 command3 等同于 command2,但由于某种原因我得到了这个异常。

Observe this simple code, using protobuf-net v2:

  interface IObject { }

  [ProtoContract]
  class Person : IObject
  {
    [ProtoMember(1)]
    public int Id { get; set; }
    [ProtoMember(2)]
    public string Name { get; set; }
    [ProtoMember(3, AsReference = true)]
    public Address Address { get; set; }
  }
  [ProtoContract]
  class Address : IObject
  {
    [ProtoMember(1)]
    public string Line1 { get; set; }
    [ProtoMember(2)]
    public string Line2 { get; set; }
  }

  class Command
  {
    public List<IObject> Objects { get; set; }
  }

  internal interface ICommandSurrogatePiece
  {
    IEnumerable<IObject> Objects { get; set; }
  }

  [ProtoContract]
  class CommandSurrogatePiece<T> : ICommandSurrogatePiece 
      where T : class, IObject
  {
    [ProtoMember(1)]
    public List<T> Objects { get; set; }

    #region ICommandSurrogatePiece Members

    IEnumerable<IObject> ICommandSurrogatePiece.Objects
    {
      get { return Objects; }
      set { Objects = value as List<T> ?? value.Cast<T>().ToList(); }
    }

    #endregion
  }

  [ProtoContract]
  class CommandSurrogate
  {
    public static implicit operator Command(CommandSurrogate surrogate)
    {
      var objects = surrogate.Pieces.SelectMany(c => c.Objects).ToList();
      return new Command { Objects = objects };
    }
    public static implicit operator CommandSurrogate(Command cmd)
    {
      var pieces = cmd.Objects.GroupBy(o => o.GetType(), 
          o => o, CreateCommandSurrogatePiece).ToList();
      return new CommandSurrogate { Pieces = pieces };
    }

    private static ICommandSurrogatePiece CreateCommandSurrogatePiece(
        Type type, IEnumerable<IObject> objects)
    {
      var piece = (ICommandSurrogatePiece)Activator.CreateInstance(
          typeof(CommandSurrogatePiece<>).MakeGenericType(type));
      piece.Objects = objects;
      return piece;
    }

    [ProtoMember(1, DynamicType = true)]
    public List<ICommandSurrogatePiece> Pieces { get; set; }
  }

  class Program
  {
    static void Main()
    {
      var person = new Person { Id = 12345, Name = "Fred", Address = 
          new Address { Line1 = "Flat 1", Line2 = "The Meadows" } };
      var person2 = new Person { Id = 2345, Name = "Fred kaka", Address = 
          new Address { Line1 = "Flat 12", Line2 = "The Meadows kuku" } };
      var address = 
          new Address { Line1 = "Flat 2", Line2 = "The Meadows Double" };
      var address2 = 
          new Address { Line1 = "Flat 2 bubub", 
              Line2 = "The Meadows Double kuku" };

      var model = TypeModel.Create();
      model.Add(typeof(CommandSurrogate), true);
      model.Add(typeof(Command), false).SetSurrogate(typeof(CommandSurrogate));
      var command = new Command { Objects = 
          new List<IObject> { person, address, person2, address2 } };
      var command2 = (Command)(CommandSurrogate)command;
      var command3 = Serializer.DeepClone(command);
    }
  }

The last line fails with an exception. What am I doing wrong?
Thanks.

EDIT

System.InvalidOperationException occurred
  Message=Type is not expected, and no contract can be inferred: HelloProtoBuf.Command
  Source=protobuf-net
  StackTrace:
       at ProtoBuf.Meta.TypeModel.ThrowUnexpectedType(Type type)
  InnerException: 

EDIT2

I have slightly modified the code to fix the surrogate code, but this does not affect the problem - it remains.

EDIT3

I am aware that command2 and command contain objects in different order. This is acceptable in my scenario. I was expecting that command3 be equivalent to command2, but for some reason I get that exception.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

狼性发作 2024-11-16 02:31:12

哦,再看一遍,这比我想象的要容易。如果您使用自定义模型,则需要使用 model 上公开的方法。 v1 API(即 Serializer.blah)现在只是 RuntimeTypeModel.Default 的间接调用。

尝试:

var command3 = (Command)model.DeepClone(command);

另请注意,新创建的对象可能以 null 形式出现 - 在我的本地重现中,我

if (cmd == null) return null;

向运算符添加了:。当我感觉不那么糟糕时,我会查看并查看库确保非空是否有意义。

Oh, on second glance this is easier than I dared hope. If you are using a custom model, you need to use the methods exposed on model. The v1 API (i.e. Serializer.blah) is now just an indirection to RuntimeTypeModel.Default.

Try:

var command3 = (Command)model.DeepClone(command);

Note also that the newly created object may come in as null - in my local repro I added:

if (cmd == null) return null;

to the operator. When I feel less grotty, I'll take and look and see if it makes sense for the library to ensure as non-null.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文