2

A DataContractSerializer will happily deserialize this class, including the readonly field:

[DataContract]
public class A
{
    public A(int rof) => Rof = rof;

    [DataMember]
    private readonly int Rof;
}

How does it do that? It has a reputation for being fast so I assume it doesn't use FieldInfo.SetValue(), does it?

Expression.Assign() doesn't seem to work, nor does emitting Stfld.

relatively_random
  • 4,505
  • 1
  • 26
  • 48
  • 3
    `stfld` can work, if you're [sufficiently devious](https://stackoverflow.com/questions/17109834/). – Jeroen Mostert Aug 03 '17 at 15:53
  • 1
    `DataContractSerializer` generates delegates to construct instances and read and set all class members by generating MSIL using tools from the [`System.Reflection.Emit`](https://msdn.microsoft.com/en-us/library/system.reflection.emit(v=vs.110).aspx), specifically the [`ILGenerator`](https://msdn.microsoft.com/en-us/library/system.reflection.emit.ilgenerator(v=vs.110).aspx). – dbc Aug 03 '17 at 22:52
  • 1
    To see how this is done, in the reference source, you can start browsing at [`ClassDataContract.XmlFormatReaderDelegate`](http://referencesource.microsoft.com/#System.Runtime.Serialization/System/Runtime/Serialization/ClassDataContract.cs,82dd061fc920c8ef). To actually set a field's value it seems `ilGen.Emit(OpCodes.Stfld, fieldInfo);` is used, see [`CodeGenerator.StoreMember()`](http://referencesource.microsoft.com/#System.Runtime.Serialization/System/Runtime/Serialization/CodeGenerator.cs,96ed34f899e0e24e,references). – dbc Aug 03 '17 at 23:02
  • 1
    And in fact protobuf-net does [exactly the same thing](https://stackoverflow.com/a/17117548/3744182) by *pretending that the method is inside the field's declaring type*. – dbc Aug 03 '17 at 23:02
  • 1
    @dbc I'd accept this if it were an answer. So I was right thinking that emitting Stfld is the way to go, but I was emitting it to a new type instead of a DynamicMethod associated with the type A. It works that way. – relatively_random Aug 04 '17 at 07:15

0 Answers0