Интерфейсы с protobuf-net и C#
Кто-нибудь знает, как правильно настроить ProtoContract для интерфейса?
Я получаю следующее исключение "Тип не может быть изменен после создания сериализатора" с использованием только атрибутов.
Используемый код:
[ProtoContract]
public class Lesson5TestClass2 : ILesson5TestInteface1
{
[ProtoMember(1)]
public string Name { get; set; }
[ProtoMember(2)]
public string Phone { get; set; }
}
[ProtoContract]
[ProtoInclude(1000, typeof(Lesson5TestClass2))]
public interface ILesson5TestInteface1
{
[ProtoMember(1)]
string Name { get; set; }
[ProtoMember(2)]
string Phone { get; set; }
}
Я могу десериализовать, только если я добавлю следующие настройки:
RuntimeTypeModel.Default.Add(typeof (ILesson5TestInteface1), true)
.AddSubType(50, typeof(Lesson5TestClass2));
Я бы очень хотел настроить это, используя только атрибуты.
Я использую Protobuf-Net R470 от NuGet.
Кстати: этот пример из серии "Уроки через тесты", показывающей, как выполнить сериализацию с protobuf-net для моих коллег.
Спасибо за прочтение:)
2 ответа
Интересно; да, похоже, что-то там наверху. Тем не менее, он работает, когда выставлен как член, т.е.
[ProtoContract]
class Wrapper
{
[ProtoMember(1)]
public ILesson5TestInteface1 Content { get; set; }
}
static class Program
{
static void Main()
{
Wrapper obj = new Wrapper
{
Content = new Lesson5TestClass2()
}, clone;
using(var ms = new MemoryStream())
{
Serializer.Serialize(ms, obj);
ms.Position = 0;
clone = Serializer.Deserialize<Wrapper>(ms);
}
// here clone.Content *is* a Lesson5TestClass2 instance
}
}
Мне придется посмотреть, что происходит с поддержкой интерфейса в качестве корневого объекта.
Самое простое решение, которое сработало для меня, - сообщить Protobuf об интерфейсе перед сериализацией фактического экземпляра.
var obj = new Lesson5TestClass2();
using var ms = new MemoryStream();
// vvv - Add this line
Serializer.PrepareSerializer<ILesson5TestInteface1>();
Serializer.Serialize(ms, obj);
ms.Position = 0;
var clone = Serializer.Deserialize<ILesson5TestInteface1>(ms);
Я предполагаю, что этот вызов заставляет Protobuf сериализовать
Lesson5TestClass2
как пример того, чего он не делает иначе, потому что у него нет возможности знать о
ILesson5TestInteface1
.
Вероятно, это также произойдет, если вы используете оболочку
class
как было предложено другим ответом (тогда Protobuf знает об интерфейсе, потому что это тип свойства, которое он проверяет перед сериализацией).
Мне бы очень хотелось настроить это, используя только атрибуты.
Это решение почти то, что вам нужно, но его все равно нужно вызывать один раз для каждого интерфейса (что лучше, чем
RuntimeTypeModel.Default.Add
так как это один раз за реализацию). Однако вы можете легко создать вспомогательный метод для вызова
PrepareSerializer
+
Serialize
combo каждый раз (не будет потери производительности, поскольку он кешируется), и он должен работать нормально, дополнительная настройка не требуется.