Tôi cần thay thế một thư viện lưu trữ dữ liệu trong các tệp (tuần tự hóa/giải tuần tự hóa) thư viện này hiện đang sử dụng BinaryFormatter để thực hiện việc đó, nhưng rất chậm với các danh sách lớn. Nhiều bài đăng trên stackoverflow chỉ ra rằng protobuf thực sự rất hiệu quả, vì vậy tôi đang cố gắng sử dụng nó.
Để thực hiện thay thế mà không cần viết lại nhiều mã, yêu cầu của tôi là:
- Dữ liệu chung phải được tuần tự hóa vì tôi phải làm việc với
Lưu trữ(T dữ liệu)
Tương tác (hầu hết thời gian T được đánh dấu bằng các thuộc tính DataContract và/hoặc Serializable)
- Tôi không thể sửa đổi tất cả các lớp đối tượng khác nhau để thêm thuộc tính protobuf, vì vậy tôi cần một phương thức chung không sử dụng các thuộc tính này
- Tôi không cần khả năng tương thích ngược: nếu lược đồ đối tượng T thay đổi (tức là thuộc tính mới), tất cả các tệp được tạo đều lỗi thời và sẽ bị xóa/được tạo lại
Việc triển khai ngây thơ đầu tiên của tôi trông như thế này:
public bool Store(khóa chuỗi, dữ liệu T)
{
var formatter = Serializer.CreateFormatter();
sử dụng (var fileStream = new FileStream(this.GetFilePath(key), FileMode.Create))
{
formatter.Serialize(fileStream, data);
trả về đúng sự thật;
}
}
Nhưng sau đó tôi nhận được ngoại lệ này:
Loại không được mong đợi và không thể suy ra hợp đồng: My.Application.Namespace.ShortcutData
Hiện tại tôi hơi bế tắc, tôi chưa tìm thấy hướng dẫn hay về cách sử dụng protobuf-net.
Có thể đạt được những yêu cầu này bằng cách sử dụng protobuf không? Bạn có một hướng dẫn tốt về cách làm điều này?
biên tập:
Vấn đề thực sự là tôi cần nói cho protobuf biết cách (hủy) tuần tự hóa dữ liệu. Đây là những gì tôi có bây giờ:
public bool Store(khóa chuỗi, dữ liệu T)
{
this.Đăng ký();
var formatter = Serializer.CreateFormatter();
sử dụng (var fileStream = new FileStream(this.GetFilePath(key), FileMode.Create))
{
formatter.Serialize(fileStream, data);
fileStream.Close();
trả về đúng sự thật;
}
}
Mã chính nằm trong phương thức Đăng ký:
Đăng ký khoảng trống được bảo vệ (Loại loại)
{
if (type.IsGenericType)
{
var đối số = type.GetGenericArguments();
foreach (đối số var trong đối số)
this.Register(đối số);
}
if (!this._registeredTypes.Contains(type) && !type.IsValueType)
{
this._registeredTypes.Add(type);
var Properties = type.GetProperties();
foreach (thuộc tính var trong thuộc tính)
{
this.Register(property.PropertyType);
}
thử
{
ProtoBuf.Meta.RuntimeTypeModel.Default
.Add(loại, sai)
.Add(thuộc tính
.Ở đâu( p => p.CanWrite)
.OrderBy(x => x.Name)
.Select(x => x.Name)
.ToArray());
}
catch
{
// Tôi gặp một vấn đề ở đây: Đôi khi tôi gặp lỗi với loại đã được đăng ký (??)
}
}
}
Tôi biết đây không phải là một mã sạch, nhưng đây chỉ là sự thay thế mã hiện có, bước thứ hai sẽ tính đến việc viết lại hoàn toàn protobuf.
Tôi mới bắt đầu thử nghiệm với Protobuf-net.. vì vậy xin đừng cho rằng câu trả lời của tôi là cách làm "đúng" theo bất kỳ cách nào. Marc Gravell chắc chắn sẽ cung cấp cho bạn câu trả lời vào một thời điểm nào đó mà bạn chắc chắn nên chú ý đến.
..Tuy nhiên, bằng chứng về khái niệm mà tôi đã viết ngày hôm trước yêu cầu tôi phải nhanh chóng sắp xếp theo thứ tự một loạt các lớp. Vì điều đó ... tôi đã nghĩ ra điều này:
var hội = Assembly.Load("Assembly.Name.Here");
foreach (loại var trong hội.GetTypes(). Where(x => typeof (IInterfaceEachClassImplements).IsAssignableFrom(x))) {
Loại thời gian chạyMô hình
.Mặc định
.Add(loại, sai)
.Add(type.GetProperties()
.Select(x => x.Name)
.ToArray());
}
Về cơ bản, nó tải từng lớp vào mô hình loại protobuf-net dựa trên giao diện mà mỗi lớp triển khai... thay vì các thuộc tính được áp dụng cho chúng.
Dù sao, hy vọng điều này sẽ chỉ cho bạn đi đúng hướng.
Tôi là một lập trình viên xuất sắc, rất giỏi!