使用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
我知道command2
和command
包含不同顺序的对象。这在我的场景中是可以接受的。我期待command3
等同于command2
,但由于某种原因,我得到了例外。
答案 0 :(得分:1)
model
上公开的方法。 v1 API(即Serializer.blah
)现在只是RuntimeTypeModel.Default
的间接。
尝试:
var command3 = (Command)model.DeepClone(command);
另请注意,新创建的对象可能会以null
的形式出现 - 在我添加的本地版本中:
if (cmd == null) return null;
给操作员。当我感觉不那么烦躁时,我会看看并确定图书馆是否有必要确保它是非空的。