属于运行时 ProtoBuf-net 模型中允许吗?
我正在使用 ProtoBuf-net 的版本 2,目前我收到错误“无法确定成员:A”
当我们使用 ClassOfType
顺便说一句:此请求是根据 使用 protobuf-net 反序列化未知类型建模的可以得到一个版本,运行得很好...但他们使用的是抽象基类,而不是 T 的泛型类。
这是一个工作示例(无法工作的内容已被删除)。
using System;
using System.IO;
using NUnit.Framework;
using ProtoBuf;
using ProtoBuf.Meta;
namespace ProtoBufTestA2
{
[TestFixture]
public class Tester
{
[Test]
public void TestMsgBaseCreateModel()
{
var BM_SD = new Container<SomeDerived>();
using (var o = BM_SD) {
o.prop1 = 42;
o.payload = new SomeDerived();
using (var d = o.payload) {
d.SomeBaseProp = -42;
d.SomeDerivedProp = 62;
}
}
var BM_SB = new Container<SomeBase>();
using (var o = BM_SB) {
o.prop1 = 42;
o.payload = new SomeBase();
using (var d = o.payload) {
d.SomeBaseProp = 84;
}
}
var model = TypeModel.Create();
model.Add(typeof(Container<SomeDerived>), true); // BM_SD
model.Add(typeof(Container<SomeBase>), true); // BM_SB
model.Add(typeof(SomeBase), true); // SB
model.Add(typeof(SomeDerived), true); // SD
model[typeof(SomeBase)].AddSubType(50, typeof(SomeDerived)); // SD
var ms = new MemoryStream();
model.SerializeWithLengthPrefix(ms, BM_SD, BM_SD.GetType(), ProtoBuf.PrefixStyle.Base128, 0);
model.SerializeWithLengthPrefix(ms, BM_SB, BM_SB.GetType(), ProtoBuf.PrefixStyle.Base128, 0);
ms.Position = 0;
var o1 = (Container<SomeDerived>)model.DeserializeWithLengthPrefix(
ms
, null
, typeof(Container<SomeDerived>), PrefixStyle.Base128, 0);
var o2 = (Container<SomeBase>)model.DeserializeWithLengthPrefix(
ms
, null
, typeof(Container<SomeBase>), PrefixStyle.Base128, 0);
}
}
[ProtoContract]
public class Container<T> : IDisposable
{
[ProtoMember(1)]
public int prop1 { get; set; }
[ProtoMember(2)]
public T payload { get; set; }
public void Dispose() { }
}
[ProtoContract]
public class AnotherDerived : SomeDerived, IDisposable
{
[ProtoMember(1)]
public int AnotherDerivedProp { get; set; }
public override void Dispose() { }
}
[ProtoContract]
public class SomeDerived : SomeBase, IDisposable
{
[ProtoMember(1)]
public int SomeDerivedProp { get; set; }
public override void Dispose() { }
}
[ProtoContract]
public class SomeBase : IDisposable
{
[ProtoMember(1)]
public int SomeBaseProp { get; set; }
public virtual void Dispose() { }
}
[ProtoContract]
public class NotInvolved : IDisposable
{
[ProtoMember(1)]
public int NotInvolvedProp { get; set; }
public void Dispose() { }
}
[ProtoContract]
public class AlsoNotInvolved : IDisposable
{
[ProtoMember(1)]
public int AlsoNotInvolvedProp { get; set; }
public void Dispose() { }
}
}
请求
话那就太好了
(Container<SomeDerived>)model.DeserializeWithLengthPrefix(...)
这是次要的,但如果也能像这样实现的
model.DeserializeWithLengthPrefix<Container<SomeDerived>>(...):
:我开始深入研究 protobuf-net 实现,并且我开始注意到一些有趣的方法像这样。我猜想稍后会回过头来:
public MetaType Add(int fieldNumber, string memberName, Type itemType, Type defaultType);
讨论:
当我在上面的链接中看到可以反序列化为抽象基本类型的方式时,我想,是的,这更接近我的想法。我们可以反序列化为开放式通用 Container<> 吗?首先,如果我们需要在不同的程序集中进行更具体的转换。也许我在这里有点混淆了。
您可以将其视为 Tuple
我有一个非通用序列正在工作,所以它不是一个表演障碍。我的第一次实施可能会更有效。我认为我可以利用现有的 protobuf-net 功能做得更好。
我喜欢用更简洁的通用方式来处理这些想法。虽然我可以手动到达相同的目的地,但泛型使其他事情成为可能。
回复:澄清
一切都可以由调用者提前定义。 (顺便说一句:你让我现在考虑仅运行时的场景,但不,我不需要那个)。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
所以我认为问题归结为“我可以使用开放泛型类型作为 protobuf 模型的模板吗”,在这种情况下答案是“也许”。 目前,它会将
BasicMsg
和BasicMsg
视为不同的类型,并且默认使用属性类型模型,因为它不会将它们识别为由[typeof(BasicMsg<>)]
定义的。如果它们有属性,它可能会起作用,但我不认为那是你的意图,对吧?这是一个有趣的场景,我愿意对此进行讨论。然而,我在这里要特别担心的是,.NET 中泛型的本质意味着这需要运行时参与,即
RuntimeTypeModel
。我认为如果不使用MakeGenericMethod
的话,我就无法让它在预编译TypeModel
上运行,而我真的想在平台和性能方面避免使用MakeGenericMethod
原因。但作为一个完整的 .NET 运行时功能,它看起来很有趣。(对上述内容进行澄清;如果调用者可以提前为
BasicMsg
定义所有T
,那么它会变得稍微更可行;那么它实际上可以归结为模型模板隐喻)So I think the question boils down to "can I use an open generic type as a template for a protobuf model", in which case the answer is "maybe". At the moment, it would see
BasicMsg<Foo>
andBasicMsg<Bar>
as different types, and it would default to using the attribute type model, since it won't recognise them as being defined by[typeof(BasicMsg<>)]
. If they have attributes, it'll probably work, but I don't think that was your intention, right?This is an interesting scenario, and I'm open to discussion on it. However, one particular concern I'd have here is that the nature of generics in .NET means this would require runtime participation, i.e.
RuntimeTypeModel
. I don't think I could get it working on pre-compiledTypeModel
without usingMakeGenericMethod
which I really want to avoid for both platform and performance reasons. But as a full-.NET runtime-only feature, it looks interesting.(clarification on the above; if the caller could define all the
T
forBasicMsg<T>
ahead of time, it becomes slightly more doable; then it really comes down to a model template metaphor)