Differences with BinaryFormatter

I am trying to change the serializer in an existing WCF net.tcp project that uses shared entities on client and server. I'm having a hard time figuring out protobuf-net (V2480) The diagram here says I can serialize private members, but can't find any documentation for that, is it possible without attributes? How to enable graph mode (as link) as described here

Will the issue of the protobuff initiating my changed item flag be resolved? For example, I have a class

 public enum FirstEnum
{ 
    First = 0,
    Second,
    Third
}
public enum AnotherEnum
{ 
    AE1 = 0,
    AE2,
    AE3
}
[Serializable()]
public class SomeClass
{
    public int SomeClassId { get; set; }
    public FirstEnum FEnum { get; set; }
    public AnotherEnum AEnum { get; set; }
    string thing;
    public string Thing
    {
        get{return thing;}
        set
        {
            if (string.IsNullOrEmpty(value))
                throw new ArgumentNullException("Thing");

            thing = value;
        }
    }

    private decimal firstAmount;
    public decimal FirstAmount 
    { 
        get{return firstAmount;} 
        set
        {
            if (value != firstAmount)
            {
                firstAmount = value;
                changedItems.Add("FirstAmount changed");
            }
        }
    }
    private decimal secondAmount;
    public decimal SecondAmount
    {
        get { return secondAmount; }
        set
        {
            if (value != secondAmount)
            {
                secondAmount = value;
                changedItems.Add("SecondAmount changed");
            }
        }
    }
    public decimal ThirdAmount { get { return SecondAmount - FirstAmount; } }
    public DateTime? SomeDate { get; set; }

    private List<string> changedItems = new List<string>();
    public List<string> ChangedItems
    {
        get { return changedItems; }
    }
public int PrivateSet { get; private set; }
    public SomeClass() { }

    public SomeClass(decimal first, decimal second)
    {
        FirstAmount = first;
        SecondAmount = second;
    }

    public void ClearChangedItems()
    {
        changedItems.Clear();
    }

      

When I deserialize it (1000 items)

 var model = CreateModel();
 items = (List<SomeClass>)model.Deserialize(returnStream, null, typeof(List<SomeClass>));

      

2012-04-06 09: 14: 28.1222 | DEBUG | ProtobufTEsts.Form1 | ProtoBuf Number of items changed: 1000

With BinaryForrmatter

System.Runtime.Serialization.Formatters.Binary.BinaryFormatter binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
items = (List<SomeClass>)binaryFormatter.Deserialize(returnStream);

      

2012-04-06 09: 14: 28.1662 | DEBUG | ProtobufTEsts.Form1 | BinaryFormatter Number of changed items: 0

Is there a way to make protobuf behave like binaryFormatter but keep protobuf performance?

How to allow private serialization, it doesn't work

 public static TypeModel CreateModel()
    {
        RuntimeTypeModel model = TypeModel.Create();
        ///var metaType = RuntimeTypeModel.Default.Add(typeof(SomeClass), false);
        model.Add(typeof(SomeClass), false)
            .Add(1, "SomeClassId")
            .Add(2, "FEnum")
            .Add(3, "AEnum")
            .Add(4, "Thing")
            .Add(5, "FirstAmount")
            .Add(6, "SecondAmount")
            .Add(7, "SomeDate")
            .Add(8, "PrivateSet");
        TypeModel compiled = model.Compile();
        return compiled;
    }

      

+3


source to share


2 answers


Ah, I understand the problem now; this line is problematic:

TypeModel compiled = model.Compile();
return compiled;

      

If you use Compile (), it creates a formal assembly (in memory) that must obey the normal assembly rules and in particular: item accessibility. This means that he cannot access your private sertter.

Use instead:



model.CompileInPlace();
return model;

      

Performs partial compilation, but continues to use DynamicMethod. This cheeky little critter has the ability to trick its rules of past access rules (like a reflection), so it can continue to use a private setter.

Note that the model is also compiled in place (at a narrower level) as needed, so this call to CompileInPlace is not absolutely necessary, but it helps to do everything in advance.

For completeness, there is an additional Compile (string, string) overload that can be used to create a separate on-disk serialization floppy that can be referenced and used without any metaprogramming at runtime.

+2


source


Yes protobuf-net can serialize private fields and do it without attributes. I'm not on a PC, so this might be required for setup:

var metaType = RuntimeTypeModel.Default.Add(typeof(SomeClass), false);
// for each field in a known order
metaType.Add(fieldName, someUniqueTag);

      

When used using attributes, there are also ImplicitFields.AllFields that automatically configure it for the use you plan to use, but I haven't added an ImplicitFields helper for the MetaType yet. I'll add this to my list!



Note. The tag values ​​(= field) are important to protobuf, and when deserializing them, it should be possible to reproduce the same number mappings.

Another option you might want to consider is (de) serialization callbacks, which let you know that it is currently being serialized / deserialized (using the before / after method). This could be another way to disable side effects for an interval such as deserialization.

0


source







All Articles