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

标签 c# .net protobuf-net

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

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

顺便说一句:此请求是根据 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<>,然后如果需要在不同的程序集中进行更具体的转换。也许我在这里有点混淆。

您可以根据 Tupple 来考虑它。或者像 Tupple> 这样的变体。它与 List 没有什么不同。我也有一些 TreeTypeThings,但我不需要对它们进行序列化/反序列化(目前)。

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

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

re: clarification

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

最佳答案

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

这是一个有趣的场景,我愿意就此展开讨论。但是,我在这里特别担心的是 .NET 中泛型的性质意味着这需要运行时参与,即 RuntimeTypeModel .我不认为我可以让它在预编译上工作 TypeModel不使用MakeGenericMethod出于平台和性能原因,我真的很想避免这种情况。但作为一个完全仅限 .NET 运行时的功能,它看起来很有趣。

(澄清以上内容;如果调用者可以提前为 T 定义所有 BasicMsg<T>,它变得稍微可行;那么它实际上归结为模型模板隐喻)

关于c# - 在运行时 ProtoBuf-net 模型中是否允许使用 <T>?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6848571/

相关文章:

c# - LINQ:如何在获取父类型的子集合时获取父类型的属性

c# - SQLite - 检索最后一行的ID

java - 与 Java 不同,为什么装箱是 .NET 未缓存的原始值类型?

c# - ASP.NET MVC - 仅发回一半的类型化 View 模型?

c# - 使用 Protocol Buffer 模拟泛型

c# - ASP.NET 中组件的许可证

c# - 在 Microsoft SQL Server 2008 中选择什么数据类型来存储纯文本?

c# - "Error while trying to run project: Unable to start program"。只能运行程序一次。然后VS需要重启

c# - 为什么枚举不使用 protobufs 反序列化?

c# - 继承和已知类型问题