"No serializer defined for type: System.Collections.HashTable" 或 "System.ComponentModel.ISite" 使用 protobuf-net 时
"No serializer defined for type: System.Collections.HashTable" or "System.ComponentModel.ISite" when using protobuf-net
我尝试在 protobuf-net 中序列化 class 时遇到以下错误。 Hashtable 包含许多不同类型的对象数组,所以不幸的是我不能使用字典。有 ISite 的派生类型,但如果接口本身是 .NET 的一部分,据我所知,我无能为力。
我查了一些关于 RuntimeTypeModel 的资料,但据我所知,它只适用于您制作的自定义 classes。任何指导将不胜感激!谢谢
Hashtable
不能正常工作的原因是它不知道你要往里面放什么。 protobuf-net 是一个基于契约的序列化器; Hashtable
本质上是 object
到 object
的映射。而 object
不是 合同——事实上,它与合同完全相反。相比之下,Dictionary<int, SomeType>
可以 正常工作(只要 SomeType
可以用作合同)。
ISite
不工作的原因是推测它是一个接口。接口代表实现,而不是数据。碰巧的是,protobuf-net 确实 对接口成员有一些有限的支持,但坦率地说,你最好让接口远离 DTO(即你的数据契约)。它应该创建什么类型的 ISite
实现?为此需要什么数据?您使用的 SomeFunSite : ISite
是如何被实例化并连接到事物上的?一个序列化器涉及的问题太多了。一个序列化器想要的是:"I'm serializing a Foo
; Foo
has 2 integers, a string, and a Bar
- although there's also the SuperBar : Bar
subclass that it needs to know about in some cases"。问题已经够多了。
好合同:
[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-net 中序列化 class 时遇到以下错误。 Hashtable 包含许多不同类型的对象数组,所以不幸的是我不能使用字典。有 ISite 的派生类型,但如果接口本身是 .NET 的一部分,据我所知,我无能为力。
我查了一些关于 RuntimeTypeModel 的资料,但据我所知,它只适用于您制作的自定义 classes。任何指导将不胜感激!谢谢
Hashtable
不能正常工作的原因是它不知道你要往里面放什么。 protobuf-net 是一个基于契约的序列化器; Hashtable
本质上是 object
到 object
的映射。而 object
不是 合同——事实上,它与合同完全相反。相比之下,Dictionary<int, SomeType>
可以 正常工作(只要 SomeType
可以用作合同)。
ISite
不工作的原因是推测它是一个接口。接口代表实现,而不是数据。碰巧的是,protobuf-net 确实 对接口成员有一些有限的支持,但坦率地说,你最好让接口远离 DTO(即你的数据契约)。它应该创建什么类型的 ISite
实现?为此需要什么数据?您使用的 SomeFunSite : ISite
是如何被实例化并连接到事物上的?一个序列化器涉及的问题太多了。一个序列化器想要的是:"I'm serializing a Foo
; Foo
has 2 integers, a string, and a Bar
- although there's also the SuperBar : Bar
subclass that it needs to know about in some cases"。问题已经够多了。
好合同:
[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;
}