FieldDecorator.cs 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. #if !NO_RUNTIME
  2. using System;
  3. using ProtoBuf.Meta;
  4. #if FEAT_IKVM
  5. using Type = IKVM.Reflection.Type;
  6. using IKVM.Reflection;
  7. #else
  8. using System.Reflection;
  9. #endif
  10. namespace ProtoBuf.Serializers
  11. {
  12. sealed class FieldDecorator : ProtoDecoratorBase
  13. {
  14. public override Type ExpectedType { get { return forType; } }
  15. private readonly FieldInfo field;
  16. private readonly Type forType;
  17. public override bool RequiresOldValue { get { return true; } }
  18. public override bool ReturnsValue { get { return false; } }
  19. public FieldDecorator(Type forType, FieldInfo field, IProtoSerializer tail) : base(tail)
  20. {
  21. Helpers.DebugAssert(forType != null);
  22. Helpers.DebugAssert(field != null);
  23. this.forType = forType;
  24. this.field = field;
  25. }
  26. #if !FEAT_IKVM
  27. public override void Write(object value, ProtoWriter dest)
  28. {
  29. Helpers.DebugAssert(value != null);
  30. value = field.GetValue(value);
  31. if(value != null) Tail.Write(value, dest);
  32. }
  33. public override object Read(object value, ProtoReader source)
  34. {
  35. Helpers.DebugAssert(value != null);
  36. object newValue = Tail.Read((Tail.RequiresOldValue ? field.GetValue(value) : null), source);
  37. if(newValue != null) field.SetValue(value,newValue);
  38. return null;
  39. }
  40. #endif
  41. #if FEAT_COMPILER
  42. protected override void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
  43. {
  44. ctx.LoadAddress(valueFrom, ExpectedType);
  45. ctx.LoadValue(field);
  46. ctx.WriteNullCheckedTail(field.FieldType, Tail, null);
  47. }
  48. protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
  49. {
  50. using (Compiler.Local loc = ctx.GetLocalWithValue(ExpectedType, valueFrom))
  51. {
  52. if (Tail.RequiresOldValue)
  53. {
  54. ctx.LoadAddress(loc, ExpectedType);
  55. ctx.LoadValue(field);
  56. }
  57. // value is either now on the stack or not needed
  58. ctx.ReadNullCheckedTail(field.FieldType, Tail, null);
  59. if (Tail.ReturnsValue)
  60. {
  61. using (Compiler.Local newVal = new Compiler.Local(ctx, field.FieldType))
  62. {
  63. ctx.StoreValue(newVal);
  64. if (Helpers.IsValueType(field.FieldType))
  65. {
  66. ctx.LoadAddress(loc, ExpectedType);
  67. ctx.LoadValue(newVal);
  68. ctx.StoreValue(field);
  69. }
  70. else
  71. {
  72. Compiler.CodeLabel allDone = ctx.DefineLabel();
  73. ctx.LoadValue(newVal);
  74. ctx.BranchIfFalse(allDone, true); // interpret null as "don't assign"
  75. ctx.LoadAddress(loc, ExpectedType);
  76. ctx.LoadValue(newVal);
  77. ctx.StoreValue(field);
  78. ctx.MarkLabel(allDone);
  79. }
  80. }
  81. }
  82. }
  83. }
  84. #endif
  85. }
  86. }
  87. #endif