Протокол ProtoInflude (1, «MyClass»)] не работает - PullRequest
4 голосов
/ 28 сентября 2011

Я использую protobuf-net v2 beta r431 для приложения на C # .net 4.0. В моем приложении у меня есть Dictionary<int, IMyClass>, который мне нужно сериализовать. Класс MyClass реализует интерфейс IMyClass. В соответствии с документацией protobuf, я написал код как:

[ProtoContract]
[ProtoInclude(1, typeof(MyClass))]
public interface IMyClass
{
    int GetId();
    string GetName();
}

[ProtoContract]
[Serializable]
public class MyClass : IMyClass
{
    [ProtoMember(1)]
    private int m_id = 0;

    [ProtoMember(2)]
    private string m_name = string.Empty;

    public MyClass(int id, string name)
    {
        m_id = id;
        m_name = name;
    }

    public MyClass()
    {
    }

    #region IMyClass Members

    public int GetId()
    {
        return m_id;
    }

    public string GetName()
    {
        return m_name;
    }

    #endregion
}

Однако, согласно дизайну моего приложения, интерфейс определен на более высоком уровне (в проекте, отличном от классов), и невозможно определить класс / классы, которые реализуют этот интерфейс во время компиляции. Следовательно, он дает ошибку времени компиляции для [ProtoInclude (1, typeof (MyClass))]. Я попытался использовать [ProtoInclude (int tag, string KownTypeName)] следующим образом:

[ProtoContract]
[ProtoInclude(1, "MyClass")]
public interface IMyClass
{
    int GetId();
    string GetName();
}

Но в строке

выдается исключение "Ссылка на объект не установлена ​​на экземпляр объекта".
Serializer.Serialize(stream, myDict);

где Dictionary myDict = new Dictionary (int, IMyClass) (); Пожалуйста, дайте мне знать, как использовать ProtoInclude в этом случае, чтобы сериализовать тип интерфейса внутри словаря / списка.

Ответы [ 2 ]

4 голосов
/ 28 сентября 2011

Поскольку он не будет знать, где взять ваш MyClass, вам, вероятно, следует использовать значение Type.AssemblyQualifiedName для вашего класса.

Вот пример кода:

namespace Alpha
{
    [ProtoContract]
    [ProtoInclude(1, "Bravo.Implementation, BravoAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")]
    //[ProtoInclude(1, "Bravo.Implementation")] // this likely only works because they're in the same file
    public class PublicInterface
    {            
    }
}

namespace  Bravo
{
    public class Implementation : Alpha.PublicInterface
    {            
    }

    public class Tests
    {
        [Test]
        public void X()
        {
            // no real tests; just testing that it runs without exceptions

            Console.WriteLine(typeof(Implementation).AssemblyQualifiedName);

            using (var stream = new MemoryStream())
            {
                Serializer.Serialize(stream, new Implementation());
            }
        }
    }
}
2 голосов
/ 28 сентября 2011

Остин прав (я полагаю): использование имени с указанием сборки (в виде строки) должно решить эту проблему.

В v2 существует дополнительная опция: вы можете выполнять сопоставление во время выполнения, а не через атрибуты:

RuntimeTypeModel.Default[typeof(PulicInterface)]
    .AddSubType(1, typeof(Implementation));

Это может быть через статический код, если ваш уровень «приложения» знает об обоих типах, или это можно сделать с помощью некоторого процесса пользовательской конфигурации / отражения.

...