public bool CanPack(Type type, BinaryDataFormat?contentBinaryFormatHint) { return(type != _model.MapType(typeof(string)) && !CanTypeBeNull(type) && !RuntimeTypeModel.CheckTypeIsCollection(_model, type) && ListDecorator.CanPack(HelpersInternal.GetWireType(HelpersInternal.GetTypeCode(type), contentBinaryFormatHint.GetValueOrDefault()))); }
private IProtoTypeSerializer BuildSerializer(bool isRoot) { // reference tracking decorators (RootDecorator, NetObjectDecorator, NetObjectValueDecorator) // should always be applied only one time (otherwise will consider new objects as already written): // #1 For collection types references are handled either by RootDecorator or // by ValueMember which owns the value (so outside of this scope) // because the value is treated as single object // #2 For members: ordinal ValueMembers are used and they will handle references when appropriate if (Helpers.IsEnum(Type)) { Debug.Assert(IsSimpleValue); IProtoTypeSerializer ser = new WireTypeDecorator(WireType.Variant, new EnumSerializer(Type, GetEnumMap())); if (isRoot && !GetRootStartsGroup()) { ser = new RootFieldNumberDecorator(ser, ListHelpers.FieldItem); } return(ser); } Type itemType = _settingsValueFinal.Member.Collection.ItemType; if (itemType != null) { if (_surrogate != null) { throw new ArgumentException("Repeated data (a list, collection, etc) has inbuilt behaviour and cannot use a surrogate"); } Type defaultType = null; ResolveListTypes(_model, Type, ref itemType, ref defaultType); if (_fields.Count != 0) { throw new ArgumentException("Repeated data (an array, list, etc) has inbuilt behavior and can't have fields"); } // apply default member settings to type settings too var s = _settingsValueFinal.Member; // but change this: s.EffectiveType = Type; // not merged with anything so assign s.Collection.ConcreteType = _settingsValueFinal.ConstructType ?? defaultType; s.Collection.Append = false; // allowed only on members s.WriteAsDynamicType = false; // allowed only on members // this should be handled as collection if (s.Collection.ItemType == null) { s.Collection.ItemType = itemType; } var vs = _rootNestedVs.Clone(); vs.SetSettings(s, 0); vs.DefaultLevel = new ValueSerializationSettings.LevelValue(s.MakeDefaultNestedLevel()); WireType wt; var ser = (IProtoTypeSerializer)_model.ValueSerializerBuilder.BuildValueFinalSerializer(vs, false, out wt); // standard root decorator won't start any field // in compatibility mode collections won't start subitems like normally // so wrap with field if (isRoot && !GetRootStartsGroup()) { ser = new RootFieldNumberDecorator(ser, TypeModel.EnumRootTag); } return(ser); } if (BaseType != null && !BaseType.GetFinalSettingsCopy().IgnoreListHandling&& RuntimeTypeModel.CheckTypeIsCollection(_model, BaseType.Type)) { throw new ArgumentException("A subclass of a repeated data (an array, list, etc should be handled too as a collection"); } // #2 if (_surrogate != null) { MetaType mt = _model[_surrogate], mtBase; while ((mtBase = mt.BaseType) != null) { mt = mtBase; } return(new SurrogateSerializer(_model, Type, _surrogate, mt.Serializer)); } if (_settingsValueFinal.IsAutoTuple) { if (_tupleCtor == null) { throw new InvalidOperationException("Can't find tuple constructor"); } return(new TupleSerializer(_model, _tupleCtor, _tupleFields.ToArray(), _settingsValueFinal.PrefixLength.GetValueOrDefault(true))); } var fields = new BasicList(_fields.Cast <object>()); fields.Trim(); int fieldCount = fields.Count; int subTypeCount = _subTypes?.Count ?? 0; int[] fieldNumbers = new int[fieldCount + subTypeCount]; IProtoSerializerWithWireType[] serializers = new IProtoSerializerWithWireType[fieldCount + subTypeCount]; int i = 0; if (subTypeCount != 0) { Debug.Assert(_subTypes != null, "_subTypes != null"); foreach (SubType subType in _subTypes) { #if WINRT if (!subType.DerivedType.IgnoreListHandling && ienumerable.IsAssignableFrom(subType.DerivedType.Type.GetTypeInfo())) #else if (!subType.DerivedType.IgnoreListHandling && _model.MapType(ienumerable).IsAssignableFrom(subType.DerivedType.Type)) #endif { throw new ArgumentException("Repeated data (a list, collection, etc) has inbuilt behaviour and cannot be used as a subclass"); } fieldNumbers[i] = subType.FieldNumber; serializers[i++] = subType.GetSerializer(_model); } } if (fieldCount != 0) { foreach (ValueMember member in fields) { fieldNumbers[i] = member.FieldNumber; serializers[i++] = member.Serializer; } } BasicList baseCtorCallbacks = null; MetaType tmp = BaseType; while (tmp != null) { MethodInfo method = tmp.HasCallbacks ? tmp.Callbacks.BeforeDeserialize : null; if (method != null) { if (baseCtorCallbacks == null) { baseCtorCallbacks = new BasicList(); } baseCtorCallbacks.Add(method); } tmp = tmp.BaseType; } MethodInfo[] arr = null; if (baseCtorCallbacks != null) { arr = new MethodInfo[baseCtorCallbacks.Count]; baseCtorCallbacks.CopyTo(arr, 0); Array.Reverse(arr); } // root serializer should be always from base type Debug.Assert(!OmitTypeSearchForRootSerialization); if (isRoot && BaseType != null) { return(new ForbiddenRootStub(Type)); } return(new TypeSerializer(_model, Type, fieldNumbers, serializers, arr, BaseType == null, !_settingsValueFinal.SkipConstructor, _callbacks, _settingsValueFinal.ConstructType, _factory, _settingsValueFinal.PrefixLength.Value)); }