public object Read(object value, ProtoReader source) { object[] values = new object[members.Length]; int tupleKey = 0; object oldTuple = null; bool issueReferenceDirectives = !baseTupleAsReference && asReference; if (issueReferenceDirectives) { tupleKey = (int)source.ReadUInt32(); if (tupleKey > 0) { return source.NetCache.GetKeyedObject(tupleKey); } else { bool dummy; oldTuple = new object(); tupleKey = source.NetCache.AddObjectKey(oldTuple, out dummy); } } bool invokeCtor = false; if (value == null) { invokeCtor = true; } for (int i = 0; i < values.Length; i++) values[i] = GetValue(value, i); int j = 0; int field; while (j++ < values.Length && source.ReadNextFieldHack() > 0) { field = source.ReadFieldHeader(); invokeCtor = true; if(field <= tails.Length) { IProtoSerializer tail = tails[field - 1]; values[field - 1] = tails[field - 1].Read(tail.RequiresOldValue ? values[field - 1] : null, source); } else { source.SkipField(); } } object result = invokeCtor ? ctor.Invoke(values) : value; if (issueReferenceDirectives) { source.NetCache.UpdateKeyedObject(tupleKey, oldTuple, result); } if (forceIssueFakeHeader) { source.ReadEndGroupFieldHeaderHack(); } return result; }