我需要替换一个在文件中存储数据的库(序列化/反序列化) 这个库目前使用BinaryFormatter,但对于大型列表来说速度很慢。 stackoverflow上的很多帖子都表明protobuf真的很高效,所以我试着用它。
为了在不重写大量代码的情况下进行替换,我的要求是:
Store<T>(T data)
接口(大部分时间T都标有DataContract和/或Serializable属性)我的第一个和天真的实现看起来像这样:
public bool Store<T>(string key, T data)
{
var formatter = Serializer.CreateFormatter<T>();
using (var fileStream = new FileStream(this.GetFilePath(key), FileMode.Create))
{
formatter.Serialize(fileStream, data);
return true;
}
}
但后来我得到了这个例外:
预计不会输入类型,也无法推断合同: My.Application.Namespace.ShortcutData
目前我有点陷入困境,我没有找到关于如何使用protobuf-net的好教程。
使用protobuf可以达到这些要求吗?你有关于如何做到这一点的好教程吗?
编辑:
问题确实是我需要告诉protobuf如何(de)序列化数据。 这就是我现在所拥有的:
public bool Store<T>(string key, T data)
{
this.Register<T>();
var formatter = Serializer.CreateFormatter<T>();
using (var fileStream = new FileStream(this.GetFilePath(key), FileMode.Create))
{
formatter.Serialize(fileStream, data);
fileStream.Close();
return true;
}
}
主要代码在Register方法中:
protected void Register(Type type)
{
if (type.IsGenericType)
{
var arguments = type.GetGenericArguments();
foreach (var argument in arguments)
this.Register(argument);
}
if (!this._registeredTypes.Contains(type) && !type.IsValueType)
{
this._registeredTypes.Add(type);
var properties = type.GetProperties();
foreach (var property in properties)
{
this.Register(property.PropertyType);
}
try
{
ProtoBuf.Meta.RuntimeTypeModel.Default
.Add(type, false)
.Add(properties
.Where( p => p.CanWrite)
.OrderBy(x => x.Name)
.Select(x => x.Name)
.ToArray());
}
catch
{
// I've a problem here: I sometime have an error for an already registered type (??)
}
}
}
我知道这不是一个干净的代码,但这只是对现有代码的替代,并且在第二步中将完全重写protobuf。
答案 0 :(得分:2)
我刚刚开始玩Protobuf-net ..所以请不要认为我的回答无论如何都是&#34;正确的&#34;做事的方式。毫无疑问,Marc Gravell会在某些方面为您提供答案,您应该注意这一点。
..然而,我前几天写的概念验证要求我得到一堆类序列化并快速完成。为此......我想出了这个:
var assembly = Assembly.Load("Assembly.Name.Here");
foreach (var type in assembly.GetTypes().Where(x => typeof (IInterfaceEachClassImplements).IsAssignableFrom(x))) {
RuntimeTypeModel
.Default
.Add(type, false)
.Add(type.GetProperties()
.Select(x => x.Name)
.ToArray());
}
基本上,它基于它们全部实现的接口将每个类加载到protobuf-net类型模型中..而不是应用于它们的属性。
希望无论如何这都指向了正确的方向。
答案 1 :(得分:2)
什么是ShortcutData
? protobuf格式不包含任何类型元数据,因此引擎必须具备有关如何映射数据的一些知识。这可以通过多种方式完成,包括通过各种属性。也可以在运行时通过涉及RuntimeTypeModel
的代码指定映射。例如,如果我们的ShortcutData
看起来像:
public class ShortcutData {
public int Key {get;set;}
public string Link {get;set;}
}
然后我们可以这样做:
[ProtoContract]
public class ShortcutData {
[ProtoMember(1)]
public int Key {get;set;}
[ProtoMember(2)]
public string Link {get;set;}
}
其中1
和2
将成为protobuf字段标识符。要序列化,您不需要使用formatter API。简单地:
public bool Store<T>(string key, T data)
{
using (var fileStream = File.Create(GetFilePath(key)))
{
Serializer.Serialize<T>(fileStream, data);
return true;
}
}