ExtensibleUtil.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using ProtoBuf.Meta;
  6. namespace ProtoBuf
  7. {
  8. /// <summary>
  9. /// This class acts as an internal wrapper allowing us to do a dynamic
  10. /// methodinfo invoke; an't put into Serializer as don't want on public
  11. /// API; can't put into Serializer&lt;T&gt; since we need to invoke
  12. /// across classes
  13. /// </summary>
  14. internal static class ExtensibleUtil
  15. {
  16. #if !NO_RUNTIME
  17. /// <summary>
  18. /// All this does is call GetExtendedValuesTyped with the correct type for "instance";
  19. /// this ensures that we don't get issues with subclasses declaring conflicting types -
  20. /// the caller must respect the fields defined for the type they pass in.
  21. /// </summary>
  22. internal static IEnumerable<TValue> GetExtendedValues<TValue>(IExtensible instance, int tag, DataFormat format, bool singleton, bool allowDefinedTag)
  23. {
  24. foreach (TValue value in GetExtendedValues(RuntimeTypeModel.Default, typeof(TValue), instance, tag, format, singleton, allowDefinedTag))
  25. {
  26. yield return value;
  27. }
  28. }
  29. #endif
  30. /// <summary>
  31. /// All this does is call GetExtendedValuesTyped with the correct type for "instance";
  32. /// this ensures that we don't get issues with subclasses declaring conflicting types -
  33. /// the caller must respect the fields defined for the type they pass in.
  34. /// </summary>
  35. internal static IEnumerable GetExtendedValues(TypeModel model, Type type, IExtensible instance, int tag, DataFormat format, bool singleton, bool allowDefinedTag)
  36. {
  37. if (instance == null) throw new ArgumentNullException(nameof(instance));
  38. if (tag <= 0) throw new ArgumentOutOfRangeException(nameof(tag));
  39. IExtension extn = instance.GetExtensionObject(false);
  40. if (extn == null)
  41. {
  42. yield break;
  43. }
  44. Stream stream = extn.BeginQuery();
  45. object value = null;
  46. ProtoReader reader = null;
  47. try
  48. {
  49. SerializationContext ctx = new SerializationContext();
  50. reader = ProtoReader.Create(stream, model, ctx, ProtoReader.TO_EOF);
  51. while (model.TryDeserializeAuxiliaryType(reader, format, tag, type, ref value, true, true, false, false, null) && value != null)
  52. {
  53. if (!singleton)
  54. {
  55. yield return value;
  56. value = null; // fresh item each time
  57. }
  58. }
  59. if (singleton && value != null)
  60. {
  61. yield return value;
  62. }
  63. }
  64. finally
  65. {
  66. ProtoReader.Recycle(reader);
  67. extn.EndQuery(stream);
  68. }
  69. }
  70. internal static void AppendExtendValue(TypeModel model, IExtensible instance, int tag, DataFormat format, object value)
  71. {
  72. if (instance == null) throw new ArgumentNullException(nameof(instance));
  73. if (value == null) throw new ArgumentNullException(nameof(value));
  74. // TODO
  75. //model.CheckTagNotInUse(tag);
  76. // obtain the extension object and prepare to write
  77. IExtension extn = instance.GetExtensionObject(true);
  78. if (extn == null) throw new InvalidOperationException("No extension object available; appended data would be lost.");
  79. bool commit = false;
  80. Stream stream = extn.BeginAppend();
  81. try
  82. {
  83. using (ProtoWriter writer = ProtoWriter.Create(stream, model, null))
  84. {
  85. model.TrySerializeAuxiliaryType(writer, null, format, tag, value, false, null);
  86. writer.Close();
  87. }
  88. commit = true;
  89. }
  90. finally
  91. {
  92. extn.EndAppend(stream, commit);
  93. }
  94. }
  95. // /// <summary>
  96. // /// Stores the given value into the instance's stream; the serializer
  97. // /// is inferred from TValue and format.
  98. // /// </summary>
  99. // /// <remarks>Needs to be public to be callable thru reflection in Silverlight</remarks>
  100. // public static void AppendExtendValueTyped<TSource, TValue>(
  101. // TypeModel model, TSource instance, int tag, DataFormat format, TValue value)
  102. // where TSource : class, IExtensible
  103. // {
  104. // AppendExtendValue(model, instance, tag, format, value);
  105. // }
  106. }
  107. }