C# &引用;没有为类型定义序列化程序:System.Collections.HashTable“;或;System.ComponentModel.ISite“;使用protobuf网络时
尝试在protobuf net中序列化类时遇到以下错误。哈希表包含许多不同类型的对象数组,所以很遗憾我不能使用字典。有ISite的派生类型,但如果接口本身是.NET的一部分,我所能做的就不多了C# &引用;没有为类型定义序列化程序:System.Collections.HashTable“;或;System.ComponentModel.ISite“;使用protobuf网络时,c#,protobuf-net,C#,Protobuf Net,尝试在protobuf net中序列化类时遇到以下错误。哈希表包含许多不同类型的对象数组,所以很遗憾我不能使用字典。有ISite的派生类型,但如果接口本身是.NET的一部分,我所能做的就不多了 我查阅了一些关于RuntimeTypeModel的资料,但据我所知,它只适用于您创建的自定义类。任何指导都将不胜感激!谢谢。哈希表之所以不能很好地工作,是因为它不知道您要在其中放入什么。protobuf net是一个基于契约的序列化程序哈希表本质上是对象-到-对象的映射。而object是而不是合同-事实上
我查阅了一些关于RuntimeTypeModel的资料,但据我所知,它只适用于您创建的自定义类。任何指导都将不胜感激!谢谢。哈希表之所以不能很好地工作,是因为它不知道您要在其中放入什么。protobuf net是一个基于契约的序列化程序
哈希表本质上是对象
-到-对象
的映射。而object
是而不是合同-事实上,它与合同完全相反。相比之下,Dictionary
可以很好地工作(只要SomeType
可以用作合同)
ISite
不起作用的原因可能是它是一个接口。接口代表实现,而不是数据。事实上,protobuf net对接口成员的支持是有限的,但坦率地说,最好让接口远离DTO(即数据契约)。它应该创建什么类型的ISite
实现?这需要什么数据?您使用的SomeFunSite:ISite
是如何被实例化和连接到事物的?序列化程序涉及的问题太多。序列化程序想要的是:“我正在序列化一个Foo
;Foo
有两个整数、一个字符串和一个Bar
——尽管在某些情况下还需要知道SuperBar:Bar
子类。”。问题已经够多了
良好合同:
[ProtoContract]
public class MyData {
[ProtoMember(1)]
public Dictionary<int, SomeType> Items {get; } = new Dictionary<int, SomeType>();
[ProtoMember(2)]
public SomethingElse Whatever { get;set;}
}
[ProtoContract]
public class MyData {
[ProtoMember(1)]
public Hashtable Items {get; } = new Hashtable();
[ProtoMember(2)]
public ISometing Whatever { get;set;}
}
在某些情况下,可能需要配置RuntimeTypeModel
来理解您要做的事情,但是:不总是这样。这取决于上下文;我没有的背景
编辑:次要澄清:
{get;}
-现在源代码中只支持属性,但在当前的NuGet构建中不支持属性-基本上,现在还不使用它
下面是一个标记存储类似数据的可运行示例:
using ProtoBuf;
using System;
using System.Collections.Generic;
static class Program
{
static void Main()
{
var obj = new MyData
{
Site = new BasicSite { BaseHost = "http://somesite.org" },
Items =
{
{"key 1", SomeType.Create(123) },
{"key 2", SomeType.Create("abc") },
{"key 3", SomeType.Create(new Whatever { Id = 456, Name = "def" }) },
}
};
var clone = Serializer.DeepClone(obj);
Console.WriteLine($"Site: {clone.Site}");
foreach(var pair in clone.Items)
{
Console.WriteLine($"{pair.Key} = {pair.Value}");
}
}
}
[ProtoContract]
class MyData
{
private readonly Dictionary<string, SomeType> _items
= new Dictionary<string, SomeType>();
[ProtoMember(1)]
public Dictionary<string, SomeType> Items => _items;
[ProtoMember(2)]
public ISite Site { get; set; }
}
[ProtoContract]
[ProtoInclude(1, typeof(SomeType<int>))]
[ProtoInclude(2, typeof(SomeType<string>))]
[ProtoInclude(3, typeof(SomeType<Whatever>))]
abstract class SomeType
{
public object Value { get { return UntypedValue; } set { UntypedValue = value; } }
protected abstract object UntypedValue { get; set; }
public static SomeType<T> Create<T>(T value) => new SomeType<T> { Value = value };
}
[ProtoContract]
class SomeType<T> : SomeType
{
[ProtoMember(1)]
public new T Value { get; set; }
protected override object UntypedValue { get => Value; set => Value = (T)value; }
public override string ToString() => Value?.ToString() ?? "";
}
[ProtoContract]
class Whatever
{
[ProtoMember(1)]
public int Id { get; set; }
[ProtoMember(2)]
public string Name { get; set; }
public override string ToString() => $"{Id}, {Name}";
}
[ProtoContract]
[ProtoInclude(1, typeof(BasicSite))]
interface ISite
{
void SomeMethod();
}
[ProtoContract]
class BasicSite : ISite
{
void ISite.SomeMethod() { Console.WriteLine(BaseHost); }
[ProtoMember(1)]
public string BaseHost { get; set; }
public override string ToString() => BaseHost;
}
使用ProtoBuf;
使用制度;
使用System.Collections.Generic;
静态类程序
{
静态void Main()
{
var obj=新的MyData
{
站点=新BasicSite{BaseHost=”http://somesite.org" },
项目=
{
{“key 1”,SomeType.Create(123)},
{“key 2”,SomeType.Create(“abc”)},
{“key 3”,SomeType.Create(新的{Id=456,Name=“def”}),
}
};
var clone=Serializer.DeepClone(obj);
Console.WriteLine($“Site:{clone.Site}”);
foreach(clone.Items中的变量对)
{
Console.WriteLine($“{pair.Key}={pair.Value}”);
}
}
}
[原始合同]
类MyData
{
专用只读字典\u项
=新字典();
[原成员(1)]
公共字典项=>\u项;
[原成员(2)]
公共ISite站点{get;set;}
}
[原始合同]
[ProtoInclude(1,typeof(SomeType))]
[ProtoInclude(2,typeof(SomeType))]
[ProtoInclude(3,typeof(SomeType))]
抽象类SomeType
{
公共对象值{get{return UntypedValue;}set{UntypedValue=Value;}}
受保护的抽象对象非类型值{get;set;}
公共静态SomeType Create(T value)=>newsometype{value=value};
}
[原始合同]
类SomeType:SomeType
{
[原成员(1)]
公共新T值{get;set;}
受保护的重写对象非类型值{get=>Value;set=>Value=(T)Value;}
公共重写字符串ToString()=>值?.ToString()?“”;
}
[原始合同]
什么课都行
{
[原成员(1)]
公共int Id{get;set;}
[原成员(2)]
公共字符串名称{get;set;}
公共重写字符串ToString()=>$“{Id},{Name}”;
}
[原始合同]
[ProtoInclude(1,类型(基硅石))]
界面云母
{
无效方法();
}
[原始合同]
基硅钙石类:硅钙石
{
void ISite.SomeMethod(){Console.WriteLine(BaseHost);}
[原成员(1)]
公共字符串BaseHost{get;set;}
公共重写字符串ToString()=>BaseHost;
}
RuntimeTypeModel适用于任何类型,而不仅仅是您创建的类。什么是ISite
?这是一个接口吗?我不认为这会奏效。。。接口是实现,而不是数据。你能更具体地说明这是什么吗?我说的哈希表基本上是一本字典。ISite变量将是从接口派生的两种类型之一,因此我可能可以在这两种派生类型上测试它。@Varun如果2ISite
实现非常简单,那么[ProtoInclude]可能可以使它全部工作。没有例子很难说。但是“(可能是多种相互不相关的类型)”不是一个好合同。不过,有一些方法可以在可靠的合同中体现这一点;例如,声明多个已知容器子类的公共基类。可以通过SomeBaseClass
和SomeDerivedClass
最方便地完成(并通过[ProtoInclude]声明各种T
)。同样,需要看一个示例来说明如何解决它。@VarunSablok我在回答中添加了一个可运行的示例序列化的一个好提示是,有时序列化的对象不是应用程序其余部分处理的对象。有时,您必须构建专门为处理好序列化和反序列化而构建的类型,而这些类型的要求可能与t完全不同