public bool GetMoreSpecificSerializer(object value, out IProtoSerializerWithWireType serializer, out int fieldNumber) { fieldNumber = 0; serializer = null; if (!CanHaveInheritance) { return(false); } Type actualType = value.GetType(); if (actualType == ExpectedType) { return(false); } for (int i = 0; i < _serializers.Length; i++) { IProtoSerializerWithWireType ser = _serializers[i]; if (ser.ExpectedType != ExpectedType && Helpers.IsAssignableFrom(ser.ExpectedType, actualType)) { serializer = ser; fieldNumber = _fieldNumbers[i]; return(true); } } if (actualType == _constructType) { return(false); // needs to be last in case the default concrete type is also a known sub-type } TypeModel.ThrowUnexpectedSubtype(ExpectedType, actualType); // might throw (if not a proxy) return(false); }
internal static ListDecorator Create( RuntimeTypeModel model, Type declaredType, Type concreteTypeDefault, IProtoSerializerWithWireType tail, bool writePacked, WireType packedWireType, bool overwriteList, bool protoCompatibility, bool writeSubType) { #if !NO_GENERICS MethodInfo builderFactory, add, addRange, finish; if (ImmutableCollectionDecorator.IdentifyImmutable(model, declaredType, out builderFactory, out add, out addRange, out finish)) { return(new ImmutableCollectionDecorator( model, declaredType, concreteTypeDefault, tail, writePacked, packedWireType, overwriteList, builderFactory, add, addRange, finish, protoCompatibility)); } #endif return(new ListDecorator(model, declaredType, concreteTypeDefault, tail, writePacked, packedWireType, overwriteList, protoCompatibility, writeSubType)); }
public UriDecorator(AqlaSerializer.Meta.TypeModel model, IProtoSerializerWithWireType tail) : base(tail) { _tail = tail; #if FEAT_IKVM expectedType = model.MapType(typeof(Uri)); #endif }
public NetObjectValueDecorator(Type type, int baseKey, bool asReference, bool asLateReference, ISerializerProxy concreteSerializerProxy, bool allowNullWireType, RuntimeTypeModel model) : this(type : type, asReference : asReference, asLateReference : asLateReference, allowNullWireType : allowNullWireType, model : model) { if (baseKey < 0) { throw new ArgumentOutOfRangeException(nameof(baseKey)); } _baseKey = baseKey; _baseKeySerializer = new ModelTypeSerializer(Helpers.GetNullableUnderlyingType(type) ?? type, baseKey, concreteSerializerProxy, model); }
public ReflectedUriDecorator(Type type, Meta.TypeModel model, IProtoSerializerWithWireType tail) : base(tail) { expectedType = type; _tail = tail; #if WINRT absoluteUriProperty = expectedType.GetTypeInfo().GetDeclaredProperty("AbsoluteUri"); typeConstructor = expectedType.GetTypeInfo().DeclaredConstructors.First(c => c.GetParameters().Length == 1 && c.GetParameters()[0].ParameterType == typeof(string)); #else absoluteUriProperty = expectedType.GetProperty("AbsoluteUri"); typeConstructor = expectedType.GetConstructor(new Type[] { typeof(string) }); #endif }
public FieldDecorator(Type forType, FieldInfo field, IProtoSerializerWithWireType tail) : base(tail) { Helpers.DebugAssert(forType != null); Helpers.DebugAssert(field != null); this._forType = forType; this._field = field; _tail = tail; #if FEAT_COMPILER && !FEAT_IKVM _accessors = AccessorsCache.GetAccessors(field); #endif }
void EmitReadTail(SerializerCodeGen g, CompilerContext ctx, IProtoSerializerWithWireType ser, Local value, Local outValueBoxed) { // inputValue may be nullable using (ctx.StartDebugBlockAuto(this)) { ser.EmitRead(ctx, ser.RequiresOldValue ? value : null); if (ser.EmitReadReturnsValue) { g.Assign(value, g.GetStackValueOperand(ser.ExpectedType)); } g.Assign(outValueBoxed, value); } }
public PropertyDecorator(TypeModel model, Type forType, PropertyInfo property, IProtoSerializerWithWireType tail) : base(tail) { Helpers.DebugAssert(forType != null); Helpers.DebugAssert(property != null); this._forType = forType; this._property = property; _tail = tail; SanityCheck(model, property, tail, out _canSetInRuntime, true, true, false); _shadowSetter = Helpers.GetShadowSetter(model, property); #if FEAT_COMPILER && !FEAT_IKVM _accessors = AccessorsCache.GetAccessors(property); if (_shadowSetter != null) { _accessors.Set = AccessorsCache.GetShadowSetter(_shadowSetter); } #endif }
public MultiDimensionalArrayDecorator(TypeModel model, IProtoSerializerWithWireType tail, Type arrayType, bool overwriteList, int readLengthLimit) : base(tail) { Helpers.DebugAssert(arrayType != null, "arrayType should be non-null"); _rank = arrayType.GetArrayRank(); if (_rank <= 1) { throw new ArgumentException("should be multi-dimension array; " + arrayType.FullName, nameof(arrayType)); } _itemType = tail.ExpectedType; if (_itemType != arrayType.GetElementType()) { throw new ArgumentException("Expected array type is " + arrayType.GetElementType() + " but tail type is " + _itemType); } _arrayType = arrayType; _overwriteList = overwriteList; _readLengthLimit = readLengthLimit; _listHelpers = new ListHelpers(false, WireType.None, false, tail, true); }
public NoNullDecorator(TypeModel model, IProtoSerializerWithWireType tail, bool throwIfNull) : base(tail) { _throwIfNull = throwIfNull; Type tailType = tail.ExpectedType; if (Helpers.IsValueType(tailType)) { #if NO_GENERICS throw new NotSupportedException("NullDecorator cannot be used with a struct without generics support"); #else _expectedType = model.MapType(typeof(Nullable <>)).MakeGenericType(tailType); #endif } else { _expectedType = tailType; } }
public ListHelpers(bool writePacked, WireType packedWireTypeForRead, bool protoCompatibility, IProtoSerializerWithWireType tail, bool skipIList) { if (protoCompatibility) { if (ListDecorator.CanPack(packedWireTypeForRead)) { _packedWireTypeForRead = packedWireTypeForRead; } else if (writePacked) { throw new ArgumentException("For writePacked wire type for read should be specified"); } _writePacked = writePacked; } _tail = tail; _skipIList = skipIList; _itemType = tail.ExpectedType; _protoCompatibility = protoCompatibility; }
public ArrayDecorator(TypeModel model, IProtoSerializerWithWireType tail, bool writePacked, WireType packedWireTypeForRead, Type arrayType, bool overwriteList, int readLengthLimit, bool protoCompatibility) : base(tail) { Helpers.DebugAssert(arrayType != null, "arrayType should be non-null"); if (!arrayType.IsArray || arrayType.GetArrayRank() != 1) { throw new ArgumentException("should be single-dimension array; " + arrayType.FullName, nameof(arrayType)); } _itemType = tail.ExpectedType; if (_itemType != arrayType.GetElementType()) { throw new ArgumentException("Expected array type is " + arrayType.GetElementType() + " but tail type is " + _itemType); } Helpers.DebugAssert(Tail.ExpectedType != model.MapType(typeof(byte)), "Should have used BlobSerializer"); _writePacked = writePacked; _arrayType = arrayType; _overwriteList = overwriteList; _protoCompatibility = protoCompatibility; _readLengthLimit = readLengthLimit; _listHelpers = new ListHelpers(_writePacked, packedWireTypeForRead, _protoCompatibility, tail, false); }
public void WriteDebugSchema(IDebugSchemaBuilder builder) { using (builder.GroupSerializer(this)) { for (int i = 0; i < _serializers.Length; i++) { IProtoSerializerWithWireType ser = _serializers[i]; if (ser.ExpectedType != ExpectedType) { using (builder.Field(_fieldNumbers[i], "SubType")) ser.WriteDebugSchema(builder); } } for (int i = 0; i < _serializers.Length; i++) { IProtoSerializerWithWireType ser = _serializers[i]; if (ser.ExpectedType == ExpectedType) { using (builder.Field(_fieldNumbers[i])) ser.WriteDebugSchema(builder); } } } }
public DefaultValueDecorator(TypeModel model, object defaultValue, IProtoSerializerWithWireType tail) : base(tail) { if (defaultValue == null) { throw new ArgumentNullException(nameof(defaultValue)); } Type type = model.MapType(defaultValue.GetType()); // if the value is nullable we should check equality with nullable before writing var underlying = Helpers.GetNullableUnderlyingType(tail.ExpectedType); if (underlying != null) { type = model.MapType(typeof(Nullable <>)).MakeGenericType(type); } if (type != tail.ExpectedType #if FEAT_IKVM // in IKVM, we'll have the default value as an underlying type && !(tail.ExpectedType.IsEnum && type == tail.ExpectedType.GetEnumUnderlyingType()) #endif ) { throw new ArgumentException(string.Format("Default value is of incorrect type (expected {0}, actaul {1})", tail.ExpectedType, type), nameof(defaultValue)); } this._defaultValue = defaultValue; }
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)); }
IProtoSerializerWithWireType BuildSerializer() { if (_serializer != null) { return(_serializer); } int opaqueToken = 0; try { // this lock is for whole model, not just this value member // so it should be taken anyway, right? _model.TakeLock(ref opaqueToken); // check nobody is still adding this type if (_serializer != null) { return(_serializer); // double check } FinalizingSettings?.Invoke(this, new FinalizingSettingsArgs(this)); if (FieldNumber < 1 && !Helpers.IsEnum(ParentType) && !_isAccessHandledOutside) { throw new ProtoException("FieldNumber < 1 for member " + Member); } if (Helpers.IsNullOrEmpty(_main.Name)) { _main.Name = Member.Name; } _vsFinal = _vsByClient.Clone(); var level0 = _vsFinal.GetSettingsCopy(0); if (level0.Basic.EffectiveType == null) { level0.Basic.EffectiveType = MemberType; } if (!level0.IsNotAssignable) { level0.IsNotAssignable = !Helpers.CanWrite(_model, Member); } _vsFinal.SetSettings(level0, 0); if (_vsFinal.DefaultValue != null && _getSpecified != null) { throw new ProtoException("Can't use default value \"" + _vsFinal.DefaultValue + "\" on member with *Specified or ShouldSerialize check " + Member); } if (_vsFinal.DefaultValue != null && IsRequired) { throw new ProtoException("Can't use default value \"" + _vsFinal.DefaultValue + "\" on Required member " + Member); } if (_getSpecified == null && !IsRequired && _vsFinal.DefaultValue == null) { if (_model.UseImplicitZeroDefaults) { switch (Helpers.GetTypeCode(MemberType)) { case ProtoTypeCode.Boolean: _vsFinal.DefaultValue = false; break; case ProtoTypeCode.Decimal: _vsFinal.DefaultValue = (decimal)0; break; case ProtoTypeCode.Single: _vsFinal.DefaultValue = (float)0; break; case ProtoTypeCode.Double: _vsFinal.DefaultValue = (double)0; break; case ProtoTypeCode.Byte: _vsFinal.DefaultValue = (byte)0; break; case ProtoTypeCode.Char: _vsFinal.DefaultValue = (char)0; break; case ProtoTypeCode.Int16: _vsFinal.DefaultValue = (short)0; break; case ProtoTypeCode.Int32: _vsFinal.DefaultValue = (int)0; break; case ProtoTypeCode.Int64: _vsFinal.DefaultValue = (long)0; break; case ProtoTypeCode.SByte: _vsFinal.DefaultValue = (sbyte)0; break; case ProtoTypeCode.UInt16: _vsFinal.DefaultValue = (ushort)0; break; case ProtoTypeCode.UInt32: _vsFinal.DefaultValue = (uint)0; break; case ProtoTypeCode.UInt64: _vsFinal.DefaultValue = (ulong)0; break; case ProtoTypeCode.TimeSpan: _vsFinal.DefaultValue = TimeSpan.Zero; break; case ProtoTypeCode.Guid: _vsFinal.DefaultValue = Guid.Empty; break; } } } #if !DEBUG try #endif { WireType wt; var ser = _model.ValueSerializerBuilder.BuildValueFinalSerializer( _vsFinal, true, out wt); if (!_isAccessHandledOutside) { PropertyInfo prop = Member as PropertyInfo; if (prop != null) { ser = new PropertyDecorator(_model, ParentType, (PropertyInfo)Member, ser); } else { FieldInfo fld = Member as FieldInfo; if (fld != null) { ser = new FieldDecorator(ParentType, (FieldInfo)Member, ser); } else { throw new InvalidOperationException(); } } if (_getSpecified != null || _setSpecified != null) { ser = new MemberSpecifiedDecorator(_getSpecified, _setSpecified, ser); } } _serializer = ser; return(ser); } #if !DEBUG catch (ProtoException ex) { throw new ProtoException(GetRethrowExceptionText(ex), ex); } catch (InvalidOperationException ex) { throw new InvalidOperationException(GetRethrowExceptionText(ex), ex); } catch (NotSupportedException ex) { throw new InvalidOperationException(GetRethrowExceptionText(ex), ex); } catch (NotImplementedException ex) { throw new NotImplementedException(GetRethrowExceptionText(ex), ex); } catch (ArgumentNullException ex) { throw new ArgumentNullException(GetRethrowExceptionText(ex), ex); } catch (ArgumentOutOfRangeException ex) { throw new ArgumentOutOfRangeException(GetRethrowExceptionText(ex), ex); } catch (ArgumentException ex) { #if SILVERLIGHT || PORTABLE throw new ArgumentException(GetRethrowExceptionText(ex), ex); #else throw new ArgumentException(GetRethrowExceptionText(ex), ex.ParamName, ex); #endif } catch (System.MissingMemberException ex) { throw new System.MissingMemberException(GetRethrowExceptionText(ex), ex); } catch (MemberAccessException ex) { throw new MemberAccessException(GetRethrowExceptionText(ex), ex); } catch (Exception ex) { throw new ProtoException(GetRethrowExceptionText(ex), ex); } #endif } finally { _model.ReleaseLock(opaqueToken); } }
IProtoSerializerWithWireType DecorateValueSerializer(Type type, BinaryDataFormat?dynamicTypeDataFormat, ref ValueFormat format, IProtoSerializerWithWireType ser) { // Uri decorator is applied after default value // because default value for Uri is treated as string if (ser.ExpectedType == _model.MapType(typeof(string)) && type == _model.MapType(typeof(Uri))) { ser = new UriDecorator(_model, ser); } #if PORTABLE else if (ser.ExpectedType == _model.MapType(typeof(string)) && type.FullName == typeof(Uri).FullName) { // In PCLs, the Uri type may not match (WinRT uses Internal/Uri, .Net uses System/Uri) ser = new ReflectedUriDecorator(type, _model, ser); } #endif if (dynamicTypeDataFormat != null) { ser = new NetObjectValueDecorator(type, format == ValueFormat.Reference || format == ValueFormat.LateReference, dynamicTypeDataFormat.Value, !_model.ProtoCompatibility.SuppressNullWireType, _model); } else if (MetaType.IsNetObjectValueDecoratorNecessary(_model, format)) { ser = new NetObjectValueDecorator( ser, Helpers.GetNullableUnderlyingType(type) != null, format == ValueFormat.Reference || format == ValueFormat.LateReference, format == ValueFormat.LateReference && CanTypeBeAsLateReferenceOnBuildStage(_model.GetKey(type, false, true), _model), !_model.ProtoCompatibility.SuppressNullWireType, _model); } else { format = ValueFormat.Compact; } return(ser); }
public IProtoSerializerWithWireType TryGetCoreSerializer(BinaryDataFormat dataFormat, Type type, out WireType defaultWireType, ref ValueFormat format, bool dynamicType, bool appendCollection, bool isPackedCollection, bool allowComplexTypes, ref object defaultValue) { if (format == ValueFormat.NotSpecified) { throw new ArgumentException("Format should be specified for TryGetCoreSerializer", nameof(format)); } if (format != ValueFormat.Compact && _model.ProtoCompatibility.SuppressValueEnhancedFormat) { throw new InvalidOperationException("TryGetCoreSerializer should receive final format with ProtoCompatibility already taken into account"); } Type originalType = type; #if !NO_GENERICS { Type tmp = Helpers.GetNullableUnderlyingType(type); if (tmp != null) { type = tmp; } } #endif defaultWireType = WireType.None; IProtoSerializerWithWireType ser = null; if (Helpers.IsEnum(type)) { if (allowComplexTypes && _model != null) { // need to do this before checking the typecode; an int enum will report Int32 etc defaultWireType = WireType.Variant; ser = new WireTypeDecorator(defaultWireType, new EnumSerializer(type, _model.GetEnumMap(type))); } else { // enum is fine for adding as a meta-type defaultWireType = WireType.None; return(null); } } if (ser == null) { ser = TryGetBasicTypeSerializer(dataFormat, type, out defaultWireType, !appendCollection); if (ser != null && Helpers.GetTypeCode(type) == ProtoTypeCode.Uri) { // should be after uri but uri should always be before collection if (defaultValue != null) { ser = new DefaultValueDecorator(_model, defaultValue, ser); defaultValue = null; } } } if (ser == null) { var parseable = _model.AllowParseableTypes ? ParseableSerializer.TryCreate(type, _model) : null; if (parseable != null) { defaultWireType = WireType.String; ser = new WireTypeDecorator(defaultWireType, parseable); } } if (ser != null) { return((isPackedCollection || !allowComplexTypes) ? ser : DecorateValueSerializer(originalType, dynamicType ? dataFormat : (BinaryDataFormat?)null, ref format, ser)); } if (allowComplexTypes) { int baseKey = _model.GetKey(type, false, true); defaultWireType = WireType.StartGroup; if (baseKey >= 0 || dynamicType) { if (dynamicType) { return(new NetObjectValueDecorator(originalType, format == ValueFormat.Reference || format == ValueFormat.LateReference, dataFormat, !_model.ProtoCompatibility.SuppressNullWireType, _model)); } else if (format == ValueFormat.LateReference && CanTypeBeAsLateReferenceOnBuildStage(baseKey, _model)) { return(new NetObjectValueDecorator(originalType, baseKey, true, true, _model[type], !_model.ProtoCompatibility.SuppressNullWireType, _model)); } else if (MetaType.IsNetObjectValueDecoratorNecessary(_model, format)) { return(new NetObjectValueDecorator(originalType, baseKey, format == ValueFormat.Reference || format == ValueFormat.LateReference, false, _model[type], !_model.ProtoCompatibility.SuppressNullWireType, _model)); } else { return(new ModelTypeSerializer(type, baseKey, _model[type], _model)); } } } defaultWireType = WireType.None; return(null); }
IProtoSerializerWithWireType BuildValueFinalSerializer(ValueSerializationSettings settings, bool isMemberOrNested, out WireType wireType, int levelNumber) { object defaultValue; var l = CompleteLevel(settings, levelNumber, out defaultValue).Basic; // to ensure that model can be copied and used again for (int i = 1; i <= 3; i++) { var l2 = CompleteLevel(settings, levelNumber, out defaultValue); Debug.Assert(l.Equals(l2.Basic)); } Debug.Assert(l.ContentBinaryFormatHint != null, "l.ContentBinaryFormatHint != null"); Debug.Assert(l.WriteAsDynamicType != null, "l.WriteAsDynamicType != null"); Debug.Assert(l.Collection.Append != null, "l.Collection.Append != null"); // postpone all checks for types when adding member till BuildSerializer, resolve everything only on buildserializer! till that have only local not inherited settings. // do not allow EnumPassthru and other settings to affect anything until buildling serializer wireType = 0; Type itemType = l.Collection.ItemType ?? l.EffectiveType; bool itemTypeCanBeNull = CanTypeBeNull(itemType); bool isPacked = CanBePackedCollection(l); IProtoSerializerWithWireType ser = null; if (l.Collection.IsCollection) { Type nestedItemType = null; Type nestedDefaultType = null; int idx = _model.FindOrAddAuto(itemType, false, true, false); MetaType type = idx < 0 ? null : _model[itemType]; if (!type?.GetFinalSettingsCopy().IgnoreListHandling ?? true) { MetaType.ResolveListTypes(_model, itemType, ref nestedItemType, ref nestedDefaultType); } bool itemIsNestedCollection = nestedItemType != null; // primitive types except System.Object may be handled as nested through recursion bool tryHandleAsRegistered = !isMemberOrNested || itemType == _model.MapType(typeof(object)); if (tryHandleAsRegistered) { var nestedLevel = settings.GetSettingsCopy(levelNumber + 1); nestedLevel = PrepareNestedLevelForBuild(nestedLevel, itemType); settings.SetSettings(nestedLevel, levelNumber + 1); // should use its level settings and merge from type, ... ser = BuildValueFinalSerializer(settings, true, out wireType, levelNumber + 1); //object dummy = null; //ser = TryGetCoreSerializer(l.ContentBinaryFormatHint.Value, nestedLevel.Basic.EffectiveType, out wireType, ref nestedLevel.Basic.Format, nestedLevel.Basic.WriteAsDynamicType.GetValueOrDefault(), l.Collection.Append.Value, isPacked, true, ref dummy); //if (ser != null) // ThrowIfHasMoreLevels(settings, levelNumber + 1, l, ", no more nested type detected"); } else if (!itemIsNestedCollection) { var nestedLevel = settings.GetSettingsCopy(levelNumber + 1); nestedLevel = PrepareNestedLevelForBuild(nestedLevel, itemType); nestedLevel.Basic.Collection.ItemType = null; // IgnoreListHandling or not a collection settings.SetSettings(nestedLevel, levelNumber + 1); ser = BuildValueFinalSerializer(settings, true, out wireType, levelNumber + 1); } if (ser == null && itemIsNestedCollection) { // if we already tried to lookup registered type no need to do it again MetaType metaType; if (_model.FindOrAddAuto(itemType, false, true, false, out metaType) >= 0) { nestedDefaultType = metaType.GetFinalSettingsCopy().ConstructType ?? nestedDefaultType ?? metaType.Type; } var nestedLevel = settings.GetSettingsCopy(levelNumber + 1); if (nestedLevel.Basic.Collection.ConcreteType == null) { nestedLevel.Basic.Collection.ConcreteType = nestedDefaultType; } if (nestedLevel.IsNotAssignable) { throw new ProtoException("Nested collection item should be assignable"); } nestedLevel.Basic.Collection.Append = false; // TODO throw if set to true: throw new ProtoException("AppendCollection is not supported for nested types: " + objectType.Name); if (nestedLevel.Basic.Collection.ItemType == null) { nestedLevel.Basic.Collection.ItemType = nestedItemType; } else if (!Helpers.IsAssignableFrom(nestedItemType, nestedLevel.Basic.Collection.ItemType)) { throw new ProtoException( "Nested collection item type " + nestedLevel.Basic.Collection.ItemType + " is not assignable to " + nestedItemType + " for declared collection type " + l.EffectiveType); } nestedLevel = PrepareNestedLevelForBuild(nestedLevel, itemType); settings.SetSettings(nestedLevel, levelNumber + 1); WireType wt; ser = BuildValueFinalSerializer( settings, true, out wt, levelNumber + 1); isPacked = false; } } else { // handled outside and not wrapped with collection if (!isMemberOrNested) { l.Format = ValueFormat.Compact; } isPacked = false; // it's not even a collection ser = TryGetCoreSerializer(l.ContentBinaryFormatHint.Value, itemType, out wireType, ref l.Format, l.WriteAsDynamicType.Value, l.Collection.Append.Value, isPacked, true, ref defaultValue); if (ser != null) { ThrowIfHasMoreLevels(settings, levelNumber, l, ", no more nested type detected"); } } if (ser == null) { throw new InvalidOperationException("No serializer defined for type: " + itemType.FullName); } if (itemTypeCanBeNull && ( (Helpers.GetNullableUnderlyingType(itemType) != null && Helpers.GetNullableUnderlyingType(ser.ExpectedType) == null) // TODO get rid of ugly casting, maybe use builder pattern || (!Helpers.IsValueType(itemType) && !(ser is NetObjectValueDecorator)) )) { // nested level may be not collection and already wrapped with nonull, may later add check whether handled as registered vs as nested if (!(ser is NoNullDecorator)) { // if not wrapped with net obj - wrap with write-null check ser = new NoNullDecorator(_model, ser, l.Collection.ItemType != null); // throw only for collection elements, otherwise don't write } } if (itemType != ser.ExpectedType && (!l.WriteAsDynamicType.Value || !Helpers.IsAssignableFrom(ser.ExpectedType, itemType))) { throw new ProtoException(string.Format("Wrong type in the tail; expected {0}, received {1}", ser.ExpectedType, itemType)); } // apply lists if appropriate if (l.Collection.IsCollection) { bool protoCompatibility = l.Collection.Format == CollectionFormat.Protobuf || l.Collection.Format == CollectionFormat.ProtobufNotPacked; WireType packedReadWt; if (!protoCompatibility) { packedReadWt = WireType.None; Debug.Assert(!isPacked); // should be determinated before passing to TryGetCoreSerializer isPacked = false; } else { packedReadWt = CanPack(l.Collection.ItemType, l.ContentBinaryFormatHint) ? l.Collection.PackedWireTypeForRead.GetValueOrDefault(wireType) : WireType.None; } if (l.EffectiveType.IsArray) { if (l.EffectiveType.GetArrayRank() == 1) { ser = new ArrayDecorator( _model, ser, isPacked, packedReadWt, l.EffectiveType, !l.Collection.Append.Value, l.Collection.ArrayLengthReadLimit.Value, protoCompatibility); } else { if (protoCompatibility) { throw new NotSupportedException("Multi-dimensional arrays are supported only in Enhanced collection format"); } ser = new MultiDimensionalArrayDecorator( _model, ser, l.EffectiveType, !l.Collection.Append.Value, l.Collection.ArrayLengthReadLimit.Value); } } else { ser = ListDecorator.Create( _model, l.EffectiveType, l.Collection.ConcreteType, ser, isPacked, packedReadWt, !l.Collection.Append.Value, protoCompatibility, true); } if (isMemberOrNested) { if (MetaType.IsNetObjectValueDecoratorNecessary(_model, l.Format)) { ser = new NetObjectValueDecorator( ser, Helpers.GetNullableUnderlyingType(l.EffectiveType) != null, l.Format == ValueFormat.Reference || l.Format == ValueFormat.LateReference, l.Format == ValueFormat.LateReference && CanTypeBeAsLateReferenceOnBuildStage(_model.GetKey(l.EffectiveType, false, true), _model), !_model.ProtoCompatibility.SuppressNullWireType, _model); } else if (!Helpers.IsValueType(l.EffectiveType) || Helpers.GetNullableUnderlyingType(l.EffectiveType) != null) { ser = new NoNullDecorator(_model, ser, false); } } if (l.EffectiveType != ser.ExpectedType && (!l.WriteAsDynamicType.Value || !Helpers.IsAssignableFrom(ser.ExpectedType, itemType))) { throw new ProtoException(string.Format("Wrong type in the tail; expected {0}, received {1}", ser.ExpectedType, itemType)); } } if (levelNumber == 0 && defaultValue != null) { ser = new DefaultValueDecorator(_model, defaultValue, ser); } return(ser); }
internal IProtoSerializerWithWireType GetSerializer(RuntimeTypeModel model) => _serializer ?? (_serializer = BuildSerializer(model));
public NetObjectValueDecorator(IProtoSerializerWithWireType tail, bool returnNullable, bool asReference, bool asLateReference, bool allowNullWireType, RuntimeTypeModel model) : this(type : MakeReturnNullable(tail.ExpectedType, returnNullable, model), asReference : asReference, asLateReference : asLateReference, allowNullWireType : allowNullWireType, model : model) { _tail = tail; RequiresOldValue = _tail.RequiresOldValue || (_lateReferenceTail?.RequiresOldValue ?? false); }
public MemberSpecifiedDecorator(MethodInfo getSpecified, MethodInfo setSpecified, IProtoSerializerWithWireType tail) : base(tail) { if (getSpecified == null && setSpecified == null) { throw new InvalidOperationException(); } this._getSpecified = getSpecified; this._setSpecified = setSpecified; }
internal ImmutableCollectionDecorator(RuntimeTypeModel model, Type declaredType, Type concreteType, IProtoSerializerWithWireType tail, bool writePacked, WireType packedWireType, bool overwriteList, MethodInfo builderFactory, MethodInfo add, MethodInfo addRange, MethodInfo finish, bool protoCompatibility) : base(model, declaredType, concreteType, tail, writePacked, packedWireType, overwriteList, protoCompatibility, false) { this._builderFactory = builderFactory; this._add = add; this._addRange = addRange; this._finish = finish; }
protected ListDecorator( RuntimeTypeModel model, Type declaredType, Type concreteTypeDefault, IProtoSerializerWithWireType tail, bool writePacked, WireType packedWireType, bool overwriteList, bool protoCompatibility, bool writeSubType) : base(tail) { if (overwriteList) { _options |= OPTIONS_OverwriteList; } PackedWireTypeForRead = packedWireType; _protoCompatibility = protoCompatibility; _writeSubType = writeSubType && !protoCompatibility; if (writePacked) { _options |= OPTIONS_WritePacked; } if (declaredType == null) { throw new ArgumentNullException(nameof(declaredType)); } if (declaredType.IsArray) { throw new ArgumentException("Cannot treat arrays as lists", nameof(declaredType)); } this.ExpectedType = declaredType; this._concreteTypeDefault = concreteTypeDefault ?? declaredType; // look for a public list.Add(typedObject) method if (RequireAdd) { bool isList; _add = TypeModel.ResolveListAdd(model, declaredType, tail.ExpectedType, out isList); if (isList) { _options |= OPTIONS_IsList; string fullName = declaredType.FullName; if (fullName != null && fullName.StartsWith("System.Data.Linq.EntitySet`1[[", StringComparison.Ordinal)) { // see http://stackoverflow.com/questions/6194639/entityset-is-there-a-sane-reason-that-ilist-add-doesnt-set-assigned _options |= OPTIONS_SuppressIList; } } if (_add == null) { throw new InvalidOperationException("Unable to resolve a suitable Add method for " + declaredType.FullName); } } ListHelpers = new ListHelpers(WritePacked, PackedWireTypeForRead, _protoCompatibility, tail, false); if (!protoCompatibility) { int key = model.GetKey(declaredType, false, false); if (key >= 0) { _metaType = model[key]; } else { _writeSubType = false; // warn? } } }