在<T>运行时ProtoBuf-net模型中是否允许?



我正在使用ProtoBuf-net的第2版,目前我得到错误"无法确定成员:A"

当我们使用classsoftype 时,是否有可能为Protobuf-net创建一个运行时模型?如果是这样,有人能发现我在下面的代码中遗漏了什么吗?

顺便说一句:这个请求是基于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);

讨论:

当我在上面的链接中看到可以反序列化为抽象基类型的方法时,我想,是的,这更接近于我的想法。我们是否可以先反序列化到开放泛型容器,然后如果需要在不同的程序集中进行更具体的强制转换?也许我有点搞混了。

你可以用tuple <TBase,TPayload>来考虑它。或者像tuple <TBase,Lazy>>这样的变体。它与List并没有太大的不同。我也有一些TreeTypeThings,但我不需要序列化/反序列化它们(目前)。

我有一个非通用序列工作,所以它不是一个显示停止。我的第一个实现可能会更有效率。我认为我可以用现有的protobuf-net功能做得更好。

我喜欢用更简洁的通用方式来处理这些想法。虽然我可以手动到达相同的目的地,但泛型使其他事情成为可能。

re:澄清

调用者可以提前定义所有内容。(顺便说一句:你现在让我想到了只运行时的场景,但是不,我不需要那个)。

所以我认为问题归结为"我可以使用开放泛型类型作为protobuf模型的模板吗?"在这种情况下,答案是"可能"。此时,它会将BasicMsg<Foo>BasicMsg<Bar>视为不同的类型,并且默认使用属性类型模型,因为它不会识别它们是由[typeof(BasicMsg<>)]定义的。如果它们属性,它可能会工作,但我不认为这是你的意图,对吗?

这是一个有趣的场景,我愿意讨论它。然而,我在这里特别关注的一个问题是,. net中泛型的性质意味着这将需要运行时参与,即RuntimeTypeModel。我不认为我可以让它在预编译的 TypeModel上工作,而不使用MakeGenericMethod,这是我真正想要避免的平台和性能原因。但作为一个完整的。. NET运行时特性,它看起来很有趣。

(以上澄清;如果调用者可以提前为BasicMsg<T>定义所有的T,它就会变得稍微可行一些;这就归结为模型模板的隐喻)

相关内容

最新更新