Можно ли (де) сериализовать частную собственность, используя protobuf-net в Silverlight? - PullRequest
2 голосов
/ 19 мая 2011

Как мы знаем, Silverlight не допускает частного отражения.Тем не менее, у меня есть открытое свойство с частным установщиком, которое мне нужно иметь для сериализации (здесь нет проблем) и десериализации (облом).

Я знаю, что ничто в мире не заставит писать protobuf-netс этим свойством в Silverlight это должно быть сделано изнутри типа клиента (или сборки, если свойство сделано внутренним).

Существует ли схема в protobuf-net для Silverlight, которая делает это возможным?Я мог бы заставить тип реализовать некоторый специализированный интерфейс protobuf-net (например, IProtoSerializable).

Спасибо.

РЕДАКТИРОВАТЬ

Я могу предложитьсхема, подобная этой:

[ProtoMember(N, SetterMethod = "DeserializePropValue")]
public string property Prop
{
  get { return m_prop; }
  private set { m_prop = value; }
}

public void DeserializePropValue(ProtoValue<string> value)
{
  m_prop = value.Value;
}

Где тип ProtoValue является открытым, но его конструкторы являются внутренними, так что только сборка protobuf-net может создавать экземпляры этого типа.И, конечно, protobuf-net не будет предоставлять какой-либо общедоступный API для создания объектов ProtoValue.

Эта схема может поддерживаться только для платформы Silverlight, другие платформы просто вызывают частный установщик.

ЧтоКак вы думаете?

EDIT2

Хочу заметить, что, безусловно, можно получить ссылку на произвольный экземпляр PropValue , но это не будет случайнои это случайные перезаписи имущества, которые я хочу устранить.Кроме того, я хочу, чтобы сеттер не был общедоступным, чтобы он не появлялся в различных механизмах связывания на основе отражений, используемых в пользовательском интерфейсе.

EDIT3

PropValue экземпляры могут быть сделаны непригодными для хранения, то есть после возврата метода DeserializePropValue соответствующий экземпляр PropValue становится недействительным.Это оставляет только один способ злоупотребить им, например:

[ProtoContract]
public class Abusee
{
    [ProtoMember(1, SetterMethod = "DeserializePropValue")]
    public string property Prop { get; private set; }

    public void DeserializePropValue(ProtoValue<string> value)
    {
      m_prop = value.Value;
    }
}

[ProtoContract]
public class Abuser
{
  private Abusee m_abusee;

  public Abuser(Abusee abusee, string newPropValue)
  {
    m_abusee = abusee;
    Dummy = newPropValue;
    Serializer.DeepClone(this);
  }

  [ProtoMember(1, SetterMethod = "DeserializeDummyValue")]
  public string property Dummy
  {
    get;
    private set;
  }

  public void DeserializeDummyValue(ProtoValue<string> value)
  {
    m_abusee.DeserializePropValue(value);
  }
}

Довольно много усилий может произойти случайно.Что касается преднамеренного насилия - здесь нет регресса.Всегда можно сериализовать объект, манипулировать двоичными данными сериализации и затем десериализовать его обратно.Регресс только в простоте злоупотребления.Однако моя цель состоит в том, чтобы:

  • Предотвращать ошибки случайно
  • Держать сеттер закрытым
  • Избегать кошмара обслуживания, связанного с суррогатами.

Ответы [ 2 ]

4 голосов
/ 19 мая 2011

Интересный вопрос. - это концепция «суррогатов» в v2, которая была разработана для неизменяемых объектов (и структур), которые могут быть полезны - это зависит от того, насколько сложным является объект, насколько привлекательной является эта опция. Второй вариант может заключаться в том, чтобы свойство показывало неизменность эскимо . Я проиллюстрирую оба, но:

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

Обратите внимание, что суррогаты нельзя указывать в атрибуте в данный момент (я мог бы добавить это позже; p) - поэтому я использовал модель времени выполнения, чтобы продемонстрировать это:

class Program
{
    static void Main()
    {
        var obj = new Popsicle(3, 4);
        var clone = Serializer.DeepClone(obj);
        Debug.Assert(clone.Foo == obj.Foo);
        Debug.Assert(clone.Bar == obj.Bar);

        var model = TypeModel.Create();
        model.Add(typeof(MutableSurrogate), false).Add("Foo", "Bar");
        model.Add(typeof(ImmutableType), false).SetSurrogate(typeof(MutableSurrogate));
        // note you should re-use models (cache them) - or better: pre-generate a serializer dll
        var obj2 = new ImmutableType(5, 6);
        var clone2 = (ImmutableType)model.DeepClone(obj2);
        Debug.Assert(clone2.Foo == obj2.Foo);
        Debug.Assert(clone2.Bar == obj2.Bar);
    }
}

[ProtoContract] // should also work with DataContract etc
public class Popsicle
{
    public Popsicle() { }
    public Popsicle(int foo, int bar)
    {
        Foo = foo;
        this.bar = bar;
    }
    private int isBeingDeserialized;

    [ProtoBeforeDeserialization]
    public void BeforeDeserialization()
    {
        isBeingDeserialized++;
    }
    [ProtoAfterDeserialization]
    public void AfterDeserialization()
    {
        isBeingDeserialized--;
    }
    [ProtoMember(1)]
    public int Foo { get; set; } //  fully mutable

    private int bar;
    [ProtoMember(2)]
    public int Bar
    {
        get { return bar; }
        set
        {
            if (bar == value) return;
            if (isBeingDeserialized <= 0) throw new InvalidOperationException();
            bar = value;
        }
    }
}

public class ImmutableType
{
    private readonly int foo, bar;
    public ImmutableType(int foo, int bar)
    {
        this.foo = foo;
        this.bar = bar;
    }
    public int Foo { get { return foo; } }
    public int Bar { get { return bar; } }
}
public class MutableSurrogate
{
    public static implicit operator ImmutableType(MutableSurrogate surrogate)
    {            
        return surrogate == null ? null
            : new ImmutableType(surrogate.Foo, surrogate.Bar);
    }
    public static implicit operator MutableSurrogate(ImmutableType surrogate)
    {
        return surrogate == null ? null
            : new MutableSurrogate { Foo = surrogate.Foo, Bar = surrogate.Bar };
    }
    public int Foo { get; set; }
    public int Bar { get; set; }
}

У меня нет ничего похожего на IProtoSerializable. Я все еще жду, чтобы найти ту вещь, которая действительно нуждается в этом ... Я не уверен, что это так.

1 голос
/ 04 февраля 2012

Похоже на Джексона - сериализатор Java Json довольно неплохо решил проблему неизменяемого класса: http://www.cowtowncoder.com/blog/archives/2010/08/entry_409.html

По существу, комментирует метод фабрики / конструктора и сопоставляет его входные параметры с неизменяемыми / доступными только для чтения свойствами.

...