using System; using System.Collections; using System.Collections.Generic; using System.IO; using ProtoBuf.Meta; namespace ProtoBuf { /// /// This class acts as an internal wrapper allowing us to do a dynamic /// methodinfo invoke; an't put into Serializer as don't want on public /// API; can't put into Serializer<T> since we need to invoke /// across classes /// internal static class ExtensibleUtil { #if !NO_RUNTIME /// /// All this does is call GetExtendedValuesTyped with the correct type for "instance"; /// this ensures that we don't get issues with subclasses declaring conflicting types - /// the caller must respect the fields defined for the type they pass in. /// internal static IEnumerable GetExtendedValues(IExtensible instance, int tag, DataFormat format, bool singleton, bool allowDefinedTag) { foreach (TValue value in GetExtendedValues(RuntimeTypeModel.Default, typeof(TValue), instance, tag, format, singleton, allowDefinedTag)) { yield return value; } } #endif /// /// All this does is call GetExtendedValuesTyped with the correct type for "instance"; /// this ensures that we don't get issues with subclasses declaring conflicting types - /// the caller must respect the fields defined for the type they pass in. /// internal static IEnumerable GetExtendedValues(TypeModel model, Type type, IExtensible instance, int tag, DataFormat format, bool singleton, bool allowDefinedTag) { if (instance == null) throw new ArgumentNullException(nameof(instance)); if (tag <= 0) throw new ArgumentOutOfRangeException(nameof(tag)); IExtension extn = instance.GetExtensionObject(false); if (extn == null) { yield break; } Stream stream = extn.BeginQuery(); object value = null; ProtoReader reader = null; try { SerializationContext ctx = new SerializationContext(); reader = ProtoReader.Create(stream, model, ctx, ProtoReader.TO_EOF); while (model.TryDeserializeAuxiliaryType(reader, format, tag, type, ref value, true, true, false, false, null) && value != null) { if (!singleton) { yield return value; value = null; // fresh item each time } } if (singleton && value != null) { yield return value; } } finally { ProtoReader.Recycle(reader); extn.EndQuery(stream); } } internal static void AppendExtendValue(TypeModel model, IExtensible instance, int tag, DataFormat format, object value) { if (instance == null) throw new ArgumentNullException(nameof(instance)); if (value == null) throw new ArgumentNullException(nameof(value)); // TODO //model.CheckTagNotInUse(tag); // obtain the extension object and prepare to write IExtension extn = instance.GetExtensionObject(true); if (extn == null) throw new InvalidOperationException("No extension object available; appended data would be lost."); bool commit = false; Stream stream = extn.BeginAppend(); try { using (ProtoWriter writer = ProtoWriter.Create(stream, model, null)) { model.TrySerializeAuxiliaryType(writer, null, format, tag, value, false, null); writer.Close(); } commit = true; } finally { extn.EndAppend(stream, commit); } } // /// // /// Stores the given value into the instance's stream; the serializer // /// is inferred from TValue and format. // /// // /// Needs to be public to be callable thru reflection in Silverlight // public static void AppendExtendValueTyped( // TypeModel model, TSource instance, int tag, DataFormat format, TValue value) // where TSource : class, IExtensible // { // AppendExtendValue(model, instance, tag, format, value); // } } }