ProtoBuf-net AsReference требуется открытый конструктор в Activator.CreateInstance? - PullRequest
4 голосов
/ 28 августа 2011

Во время работы над двумя моими классами это выглядит так (минимально)

using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using ProtoBuf;

namespace Sandbox
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            Family family = new Family();
            Child child1 = new Child(1);
            Child child2 = new Child(2);
            Parent parent = new Parent(new List<Child>() { child1, child2 });
            family.Add(parent);

            string file = "sandbox.txt";

            try { File.Delete(file); } catch { }

            using (var fs = File.OpenWrite(file)) { Serializer.Serialize(fs, family); }
            using (var fs = File.OpenRead(file)) { family = Serializer.Deserialize<Family>(fs); }

            System.Diagnostics.Debug.Assert(family != null, "1. Expect family not null, but not the case.");
        }
    }

    [ProtoContract()]
    public class Child
    {
        [ProtoMember(1, AsReference = true)]
        internal Parent Parent;

        private Child() { }

        public Child(int i) { }
    }

    [ProtoContract()]
    public class Parent
    {
        [ProtoMember(1)]
        protected List<Child> m_Children;

        /// <summary>
        /// ProtoBuf deserialization constructor (fails here)
        /// </summary>
        private Parent() { m_Children = new List<Child>(); }

        public Parent(List<Child> children)
        {
            m_Children = children;
            m_Children.ForEach(x => x.Parent = this);
        }
    }

    [ProtoContract()]
    public class Family
    {
        [ProtoMember(1)]
        protected List<Parent> m_Parents;

        public void Add(Parent parent)
        {
            m_Parents.Add(parent);
        }

        public Family()
        {
            m_Parents = new List<Parent>();
        }
    }
}

Во время десериализации я сталкиваюсь с исключением: «Для этого объекта не определен конструктор без параметров». для создания родительского объекта в ProtoBuf.BclHelper около

case FieldObject:
// ...
value = ((options & NetObjectOptions.UseConstructor) == 0) ? BclHelpers.GetUninitializedObject(type) : Activator.CreateInstance(type);

Затем, когда я изменил конструктор по умолчанию Parent () на public, исключение пропало.

Есть идеи о том, что я мог упустить из виду , является ли в данном случае правильным использование AsRerference?

BOUNTY : В то время как Марк не торопится с решением этой проблемы, мне потребуется определенное решение для использования protobuf-net в этой ситуации, обходя его либо с помощью атрибутов protobuf-net, методов или других приемов. В противном случае мне придется полностью отказаться от использования protobuf-net. Спасибо за любую помощь.

Ответы [ 2 ]

3 голосов
/ 22 сентября 2011

Я считаю, что вы можете сделать это, чтобы решить эту проблему:

[ProtoContract(SkipConstructor = true)]
public class Parent
{
    [ProtoMember(1)]
    protected List<Child> m_Children;

    private Parent() { Initialize(); }

    [ProtoBeforeDeserialization] // could also use OnDeserializing
    private void Initialize()
    {
        m_Children = new List<Child>();
    }

    public Parent(List<Child> children)
    {
        m_Children = children;
        m_Children.ForEach(x => x.Parent = this);
    }

}

1 голос
/ 28 августа 2011

При десериализации Parent вам нужен открытый конструктор без параметров. Итак, ваш минимальный тестовый пример, который не проходит: создайте Child с ненулевым m_Parent, сериализуйте его и десериализуйте результат.

...