public TupleSerializer(RuntimeTypeModel model, ConstructorInfo ctor, MemberInfo[] members, bool asReference,
							   bool baseTupleAsReference, bool forceIssueFakeHeader, bool useDynamicTypeWhenNeeded, bool supportNull)
        {
            if (ctor == null) throw new ArgumentNullException("ctor");
            if (members == null) throw new ArgumentNullException("members");
            this.ctor = ctor;
            this.members = members;
            this.tails = new IProtoSerializer[members.Length];
        	this.asReference = asReference;
        	this.baseTupleAsReference = baseTupleAsReference;
			this.forceIssueFakeHeader = forceIssueFakeHeader;

            ParameterInfo[] parameters = ctor.GetParameters();
            for(int i = 0 ; i < members.Length ; i++)
            {
                WireType wireType;
                Type finalType = parameters[i].ParameterType;

                Type itemType = null, defaultType = null;

                MetaType.ResolveListTypes(finalType, ref itemType, ref defaultType);
                Type tmp = itemType == null ? finalType : itemType;

				bool dynamicType = useDynamicTypeWhenNeeded && (tmp.IsInterface || tmp == typeof(object));
            	bool overrideSkipConstructor = i == 7; // if there are 8 class parameters the last one has to be a tuple

				IProtoSerializer tail =
					ValueMember.TryGetCoreSerializer(model, DataFormat.Default, tmp, out wireType, asReference, dynamicType, false, overrideSkipConstructor, supportNull), serializer;
                if (tail == null) throw new InvalidOperationException("No serializer defined for type: " + tmp.FullName);

				if (itemType != null && supportNull)
				{
					tail = new TagDecorator(NullDecorator.Tag, wireType, false, tail);
					tail = new NullDecorator(tail);
					tail = new TagDecorator(i + 1, WireType.StartGroup, false, tail);
				}
				else
				{
					tail = new TagDecorator(i + 1, wireType, false, tail);					
				}
				
                if(itemType == null)
                {
                    serializer = tail;
                }
                else
                {
                    if (finalType.IsArray)
                    {
						serializer = new ArrayDecorator(tail, i + 1, false, wireType, finalType, false, supportNull, asReference, false);
                    }
                    else
                    {
                    	serializer = new ListDecorator(finalType, defaultType, tail, i + 1, false, wireType, true,
													   false, supportNull, asReference, false, false);
                    }
                }
                tails[i] = serializer;
            }
        }
		private IProtoSerializer GetNestedSerializer(BasicList nestedHierarchy, out WireType wireType)
		{
			IProtoSerializer ser = null;
			int listCount = nestedHierarchy.Count;
			wireType = WireType.None;
			bool hasAutoDynamicHandling = HasAutoDynamicHandling(nestedHierarchy);

			for (int i = listCount - 1; i >= 0; i--)
			{
				NestedItem item = (NestedItem)nestedHierarchy[i];

				if (item.ItemType == null)
				{
					bool isDynamic = dynamicType;
					bool requiresDynamic = item.Type.IsInterface || item.Type == typeof (object);

					if (!isDynamic && autoDynamicType && requiresDynamic)
					{
						isDynamic = true;
					}
					else if (hasAutoDynamicHandling && requiresDynamic)
					{
						// for now just set isDynamic to true
						isDynamic = true;
					}

					ser = TryGetCoreSerializer(model, dataFormat, item.Type, out wireType, asReference, /*dynamicType*/isDynamic, OverwriteList, false, SupportNull);
					if (ser == null) throw new InvalidOperationException("No serializer defined for type: " + item.Type.FullName);

					if (listCount == 1)
					{
						ser = new TagDecorator(fieldNumber, wireType, IsStrict, ser);
					}
				}
				else
				{
					if (SupportNull)
					{
						if (IsPacked)
						{
							throw new NotSupportedException("Packed encodings cannot support null values");
						}
						ser = new TagDecorator(NullDecorator.Tag, wireType, IsStrict, ser);
						ser = new NullDecorator(ser);
						ser = new TagDecorator(fieldNumber, WireType.StartGroup, false, ser);
					}
					else
					{
						ser = new TagDecorator(fieldNumber, wireType, IsStrict, ser);
					}

					bool nested = listCount > 2 && i >= 1;

					if (item.Type.IsArray)
					{
						ser = new ArrayDecorator(ser, fieldNumber, IsPacked, wireType, item.Type, OverwriteList, SupportNull, AsReference, nested);
					}
					else
					{
						ser = new ListDecorator(item.Type, item.DefaultType, ser, fieldNumber, IsPacked, wireType,
															  member == null || PropertyDecorator.CanWrite(member), OverwriteList,
															  SupportNull, AsReference, nested, isValueMemberForCollectionBasedTypes);
					}
				}
			}

			return ser;
		}
Exemplo n.º 3
0
        private IProtoSerializer BuildSerializer()
        {
            int opaqueToken = 0;
            try
            {
                model.TakeLock(ref opaqueToken);// check nobody is still adding this type
                WireType wireType;
                Type finalType = itemType == null ? memberType : itemType;
                IProtoSerializer ser = TryGetCoreSerializer(model, dataFormat, finalType, out wireType, asReference, dynamicType);
                if (ser == null) throw new InvalidOperationException("No serializer defined for type: " + finalType.FullName);
                // apply tags
                if (itemType != null && SupportNull)
                {
                    if(IsPacked)
                    {
                        throw new NotSupportedException("Packed encodings cannot support null values");
                    }
                    ser = new TagDecorator(NullDecorator.Tag, wireType, IsStrict, ser);
                    ser = new NullDecorator(ser);
                    ser = new TagDecorator(fieldNumber, WireType.StartGroup, false, ser);
                }
                else
                {
                    ser = new TagDecorator(fieldNumber, wireType, IsStrict, ser);
                }
                // apply lists if appropriate
                if (itemType != null)
                {                    
#if NO_GENERICS
                    Type underlyingItemType = itemType;
#else
                    Type underlyingItemType = SupportNull ? itemType : Nullable.GetUnderlyingType(itemType) ?? itemType;
#endif
                    Helpers.DebugAssert(underlyingItemType == ser.ExpectedType, "Wrong type in the tail; expected {0}, received {1}", ser.ExpectedType, underlyingItemType);
                    if (memberType.IsArray)
                    {
                        ser = new ArrayDecorator(ser, fieldNumber, IsPacked, wireType, memberType, OverwriteList, SupportNull);
                    }
                    else
                    {
                        ser = new ListDecorator(memberType, defaultType, ser, fieldNumber, IsPacked, wireType, member == null || PropertyDecorator.CanWrite(member), OverwriteList, SupportNull);
                    }
                }
                else if (defaultValue != null && !IsRequired)
                {
                    ser = new DefaultValueDecorator(defaultValue, ser);
                }
                if (memberType == typeof(Uri))
                {
                    ser = new UriDecorator(ser);
                }
                if (member != null)
                {
                    switch (member.MemberType)
                    {
                        case MemberTypes.Property:
                            ser = new PropertyDecorator(parentType, (PropertyInfo)member, ser); break;
                        case MemberTypes.Field:
                            ser = new FieldDecorator(parentType, (FieldInfo)member, ser); break;
                        default:
                            throw new InvalidOperationException();
                    }
                    if (getSpecified != null || setSpecified != null)
                    {
                        ser = new MemberSpecifiedDecorator(getSpecified, setSpecified, ser);
                    }
                }
                return ser;
            }
            finally
            {
                model.ReleaseLock(opaqueToken);
            }
        }