属于运行时 ProtoBuf-net 模型中允许吗?

发布于 2024-11-26 21:42:50 字数 4591 浏览 0 评论 0 原文

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

当我们使用 ClassOfType 时是否可以为 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);

讨论:

当我在上面的链接中看到可以反序列化为抽象基本类型的方式时,我想,是的,这更接近我的想法。我们可以反序列化为开放式通用 Container<> 吗?首先,如果我们需要在不同的程序集中进行更具体的转换。也许我在这里有点混淆了。

您可以将其视为 Tuple。或者像 Tupple> 这样的变体或许。它与 List 没有什么不同。有一些 TreeTypeThings我也有,但我不需要序列化/反序列化它们(还)。

我有一个非通用序列正在工作,所以它不是一个表演障碍。我的第一次实施可能会更有效。我认为我可以利用现有的 protobuf-net 功能做得更好。

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

回复:澄清

一切都可以由调用者提前定义。 (顺便说一句:你让我现在考虑仅运行时的场景,但不,我不需要那个)。

I am using version 2 of ProtoBuf-net, and currently I'm geting the error "Unable to determine member: A"

Is it possible to create a run-time model for Protobuf-net when we use ClassOfType<T>? If so, can anyone spot what I'm missing in the below code?

btw: this request is modelled off of Deserialize unknown type with protobuf-net I could get a version of this going just fine... but they are using an abstract base class, not a generic class of T.

THIS IS A WORKING EXAMPLE (stuff that wasn't working is removed).

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() { }
    }
}

Request

This is minor, but it'd be nice if

  (Container<SomeDerived>)model.DeserializeWithLengthPrefix(...) 

could also be implemented like this

  model.DeserializeWithLengthPrefix<Container<SomeDerived>>(...):

btw: I'm starting to dig into the protobuf-net implementation, and I'm starting to notice some interesting methods like this. Something to come back to later I guess:

  public MetaType Add(int fieldNumber, string memberName, Type itemType, Type defaultType);

Discussion:

when I saw the way you could deserialize to an abstract base type in the link above, I thought, yes, that's closer to what was thinking. Could we deserialize to the open generic Container<> first, and then cast more specifically if we need to in different assemblies. Maybe I'm getting mixed up a little here.

You could think of it in terms of Tupple<TBase,TPayload>. Or a variation like Tupple<TBase,Lazy<TPayload>> maybe. It's not that different to List<T>. There are some TreeTypeThings<T> that I have too, but I don't need to serialize/deserialize them (yet).

I had a non-generic sequence working, so it isn't a show stopper. My first implementation could be more efficient. I think I can do better on that with existing protobuf-net features though.

I like the cleaner generic way of working with these ideas. Although I can get to the same destination manually, Generics make other things possible.

re: clarification

everything can be defined ahead of time by the caller. (btw: You've got me thinking about the run-time only scenario now, but no, I don't need that).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

独自唱情﹋歌 2024-12-03 21:42:50

所以我认为问题归结为“我可以使用开放泛型类型作为 protobuf 模型的模板吗”,在这种情况下答案是“也许”。 目前,它会将 BasicMsgBasicMsg 视为不同的类型,并且默认使用属性类型模型,因为它不会将它们识别为由 [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> and BasicMsg<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-compiled TypeModel without using MakeGenericMethod 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 for BasicMsg<T> ahead of time, it becomes slightly more doable; then it really comes down to a model template metaphor)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文