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

时间:2011-07-27 17:23:32

标签: c# .net protobuf-net

我正在使用ProtoBuf-net的第2版,目前我正在发出错误“无法确定成员:A”

当我们使用ClassOfType&lt; T&gt;时,是否可以为Protobuf-net创建运行时模型?如果是这样,有人可以在下面的代码中发现我缺少的内容吗?

btw:这个请求是以Deserialize unknown type with 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&lt;&gt;首先,如果我们需要在不同的程序集中,则更具体地进行转换。也许我在这里混淆了一点。

您可以根据Tupple&lt; TBase,TPayload&gt;来考虑它。或者像Tupple&lt; TBase,Lazy&lt; TPayload&gt;&gt;的变化。也许。它与List&lt; T&gt;没有什么不同。有一些TreeTypeThings&lt; T&gt;我也有,但我不需要序列化/反序列化(还)。

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

我喜欢使用这些想法的更清晰的通用方法。虽然我可以手动到达同一目的地,但是泛型可以使其他事情成为可能。

  

re:澄清

呼叫者可以提前定义所有内容。 (顺便说一下:你现在让我考虑了仅限运行时的情况,但不,我不需要那样)。

1 个答案:

答案 0 :(得分:4)

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

这是一个有趣的场景,我愿意讨论它。但是,我在这里遇到的一个特定问题是,.NET中泛型的本质意味着这需要运行时参与,即RuntimeTypeModel。我不认为我可以在不使用TypeModel的情况下使用预编译 MakeGenericMethod,因为平台和性能方面的原因我真的想避免使用T。但作为一个完整的.NET运行时功能,它看起来很有趣。

(对上述内容的澄清;如果调用者可以提前为BasicMsg<T>定义所有{{1}},那么它会变得更加可行;那么它实际上归结为模型模板的隐喻)