/// <summary> /// Stores the given value into the instance's stream; the serializer /// is inferred from TValue and format. /// </summary> /// <remarks>Needs to be public to be callable thru reflection in Silverlight</remarks> public static void AppendExtendValueTyped <TSource, TValue>( TSource instance, int tag, DataFormat format, TValue value) where TSource : class, IExtensible { Serializer <TSource> .CheckTagNotInUse(tag); Property <TValue, TValue> prop = PropertyFactory.CreatePassThru <TValue>(tag, ref format); IExtension extn = instance.GetExtensionObject(true); if (extn == null) { throw new InvalidOperationException("No extension object available; appended data would be lost."); } Stream stream = extn.BeginAppend(); try { SerializationContext ctx = new SerializationContext(stream, null); ctx.Push(instance); // for recursion detection prop.Serialize(value, ctx); ctx.Pop(instance); ctx.Flush(); extn.EndAppend(stream, true); } catch { extn.EndAppend(stream, false); throw; } }
/// <summary> /// Reads the given value(s) from the instance's stream; the serializer /// is inferred from TValue and format. For singletons, each occurrence /// is merged [only applies for sub-objects], and the composed /// value if yielded once; otherwise ("repeated") each occurrence /// is yielded separately. /// </summary> /// <remarks>Needs to be public to be callable thru reflection in Silverlight</remarks> public static IEnumerable <TValue> GetExtendedValuesTyped <TSource, TValue>( TSource instance, int tag, DataFormat format, bool singleton, bool allowDefinedTag) where TSource : class, IExtensible { if (instance == null) { throw new ArgumentNullException("instance"); } if (!allowDefinedTag) { Serializer <TSource> .CheckTagNotInUse(tag); } Property <TValue, TValue> prop = PropertyFactory.CreatePassThru <TValue>(tag, ref format); List <Property <TValue, TValue> > props = new List <Property <TValue, TValue> >(); foreach (Property <TValue, TValue> altProp in prop.GetCompatibleReaders()) { props.Add(altProp); } IExtension extn = instance.GetExtensionObject(false); if (extn == null) { yield break; } Stream stream = extn.BeginQuery(); TValue lastValue = default(TValue); bool hasValue = false; try { SerializationContext ctx = new SerializationContext(stream, null); uint fieldPrefix; while (ctx.TryReadFieldPrefix(out fieldPrefix)) { WireType a; int b; Serializer.ParseFieldToken(fieldPrefix, out a, out b); Property <TValue, TValue> actProp = null; if (fieldPrefix == prop.FieldPrefix) { actProp = prop; } else { foreach (Property <TValue, TValue> x in props) { if (x.FieldPrefix == fieldPrefix) { actProp = x; break; } } } if (actProp != null) { TValue value = actProp.DeserializeImpl(lastValue, ctx); hasValue = true; if (singleton) { // merge with later values before returning lastValue = value; } else { // return immediately; no merge yield return(value); } } else { int readTag; WireType wireType; Serializer.ParseFieldToken(fieldPrefix, out wireType, out readTag); if (readTag == tag) { // we can't deserialize data of that type - for example, // have received Fixed32 for a string, etc throw new ProtoException(string.Format( "Unexpected wire-type ({0}) found for tag {1}.", wireType, readTag)); } // skip all other tags Serializer.SkipData(ctx, readTag, wireType); } } } finally { extn.EndQuery(stream); } if (singleton && hasValue) { yield return(lastValue); } }