使用protobuf-net代理有什么问题?

时间:2011-05-23 07:08:15

标签: .net protobuf-net

使用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: 

EDIT2

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

EDIT3

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

1 个答案:

答案 0 :(得分:1)

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

尝试:

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

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

if (cmd == null) return null;

给操作员。当我感觉不那么烦躁时,我会看看并确定图书馆是否有必要确保它是非空的。