Пример #1
0
        /// <summary>
        /// Responsible for deciding how to encode/decode a given data-type; maybe
        /// not the most elegant solution, but it is simple and quick.
        /// </summary>
        private static Property <T> CreateProperty <T>(Type type, ref DataFormat format, MemberSerializationOptions options)
        {
            if (type.IsEnum)
            {
                if (format != DataFormat.Default && Attribute.IsDefined(type, typeof(FlagsAttribute)))
                {
                    type = Enum.GetUnderlyingType(type);
                }
                else
                {
                    format = DataFormat.TwosComplement;
                    return(PropertyUtil <T> .CreateTypedProperty("CreatePropertyEnum", type));
                }
            }

            if (type == typeof(int))
            {
                switch (format)
                {
                case DataFormat.Default:
                case DataFormat.TwosComplement:
                    format = DataFormat.TwosComplement;
                    return(new PropertyInt32Variant <T>());

                case DataFormat.ZigZag:
                    return(new PropertyInt32ZigZag <T>());

                case DataFormat.FixedSize:
                    return(new PropertyInt32Fixed <T>());
                }
            }
            if (type == typeof(short))
            {
                switch (format)
                {
                case DataFormat.Default:
                case DataFormat.TwosComplement:
                    format = DataFormat.TwosComplement;
                    return(new PropertyInt16Variant <T>());

                case DataFormat.ZigZag:
                    return(new PropertyInt16ZigZag <T>());
                }
            }
            if (type == typeof(long))
            {
                switch (format)
                {
                case DataFormat.Default:
                case DataFormat.TwosComplement:
                    format = DataFormat.TwosComplement;
                    return(new PropertyInt64Variant <T>());

                case DataFormat.ZigZag:
                    return(new PropertyInt64ZigZag <T>());

                case DataFormat.FixedSize:
                    return(new PropertyInt64Fixed <T>());
                }
            }
            if (type == typeof(uint))
            {
                switch (format)
                {
                case DataFormat.Default:
                case DataFormat.TwosComplement:
                    format = DataFormat.TwosComplement;
                    return(new PropertyUInt32Variant <T>());

                case DataFormat.FixedSize:
                    return(new PropertyUInt32Fixed <T>());
                }
            }
            if (type == typeof(ulong))
            {
                switch (format)
                {
                case DataFormat.Default:
                case DataFormat.TwosComplement:
                    format = DataFormat.TwosComplement;
                    return(new PropertyUInt64Variant <T>());

                case DataFormat.FixedSize:
                    return(new PropertyUInt64Fixed <T>());
                }
            }

            if (type == typeof(ushort))
            {
                switch (format)
                {
                case DataFormat.Default:
                case DataFormat.TwosComplement:
                    format = DataFormat.TwosComplement;
                    return(new PropertyUInt16Variant <T>());
                }
            }

            if (type == typeof(byte[]))
            {
                format = DataFormat.Default; return(new PropertyBlob <T>());
            }
            if (type == typeof(byte))
            {
                format = DataFormat.TwosComplement; return(new PropertyByte <T>());
            }
            if (type == typeof(sbyte))
            {
                format = DataFormat.ZigZag; return(new PropertySByte <T>());
            }
            if (type == typeof(char))
            {
                format = DataFormat.TwosComplement; return(new PropertyChar <T>());
            }
            if (type == typeof(bool))
            {
                format = DataFormat.TwosComplement; return(new PropertyBoolean <T>());
            }
            if (type == typeof(string))
            {
                format = DataFormat.Default; return(new PropertyString <T>());
            }
            if (type == typeof(float))
            {
                format = DataFormat.FixedSize; return(new PropertySingle <T>());
            }
            if (type == typeof(double))
            {
                format = DataFormat.FixedSize; return(new PropertyDouble <T>());
            }
            if (type == typeof(Uri))
            {
                format = DataFormat.Default; return(new PropertyUri <T>());
            }

            if (type == typeof(Guid))
            {
                switch (format)
                {
                case DataFormat.Group: return(new PropertyGuidGroup <T>());

                case DataFormat.Default: return(new PropertyGuidString <T>());
                }
            }
            if (type == typeof(TimeSpan))
            {
                switch (format)
                {
                case DataFormat.Group: return(new PropertyTimeSpanGroup <T>());

                case DataFormat.Default: return(new PropertyTimeSpanString <T>());

                case DataFormat.FixedSize: return(new PropertyTimeSpanFixed <T>());
                }
            }
            if (type == typeof(DateTime))
            {
                switch (format)
                {
                case DataFormat.Group: return(new PropertyDateTimeGroup <T>());

                case DataFormat.Default: return(new PropertyDateTimeString <T>());

                case DataFormat.FixedSize: return(new PropertyDateTimeFixed <T>());
                }
            }
            if (type == typeof(decimal))
            {
                switch (format)
                {
                case DataFormat.Group: return(new PropertyDecimalGroup <T>());

                case DataFormat.Default: return(new PropertyDecimalString <T>());
                }
            }


            if (Serializer.IsEntityType(type))
            {
                Type baseType = type;
                while (Serializer.IsEntityType(baseType.BaseType))
                {
                    baseType = baseType.BaseType;
                }
                switch (format)
                {
                case DataFormat.Default: return(PropertyUtil <T> .CreateTypedProperty("CreatePropertyMessageString", type, baseType, baseType));

                case DataFormat.Group: return(PropertyUtil <T> .CreateTypedProperty("CreatePropertyMessageGroup", type, baseType, baseType));
                }
            }

            if (type.IsValueType && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(KeyValuePair <,>))
            {
                return(PropertyUtil <T> .CreateTypedProperty("CreatePropertyPairString", type.GetGenericArguments()));
            }
            bool isEnumerableOnly;
            Type listItemType = GetListType(type, out isEnumerableOnly);

            if (type.IsArray)
            {
                // verify that we can handle it
                if (type.GetArrayRank() != 1)
                {
                    throw new NotSupportedException("Only 1-dimensional arrays can be used; consider an array/list of a class-type instead");
                }
            }

            if (listItemType != null && listItemType != typeof(byte[]))
            {
                bool dummy;
                if (GetListType(listItemType, out dummy) != null)
                {
                    throw new NotSupportedException("Nested (jagged) arrays/lists are not supported (except for byte[]); consider an array/list of a class-type with an inner array/list instead");
                }
            }


            if (type == typeof(byte[]))
            {   // want to treat byte[] as a special case
                listItemType = null;
            }
            if (type.IsArray && listItemType != null) // second check is for byte[]
            {
                return(PropertyUtil <T> .CreateTypedProperty(
                           (PropertyFactory.HasOption(options, MemberSerializationOptions.Packed)
                        ? "CreatePropertyPackedArray" : "CreatePropertyArray"), listItemType));
            }

            if (listItemType != null)
            {
                if (isEnumerableOnly)
                {
                    if (GetAddMethod(type, listItemType) != null)
                    {
                        return(PropertyUtil <T> .CreateTypedProperty(
                                   (PropertyFactory.HasOption(options, MemberSerializationOptions.Packed)
                            ? "CreatePropertyPackedEnumerable" : "CreatePropertyEnumerable"), type, listItemType));
                    }
                }
                else
                {
                    return(PropertyUtil <T> .CreateTypedProperty(
                               (PropertyFactory.HasOption(options, MemberSerializationOptions.Packed)
                        ? "CreatePropertyPackedList" : "CreatePropertyList"), type, listItemType));
                }
            }

            Type nullType = Nullable.GetUnderlyingType(type);

            if (nullType != null)
            {
                return(PropertyUtil <T> .CreateTypedProperty("CreatePropertyNullable", nullType));
            }

            if (format == DataFormat.Default && GetParseMethod(type) != null)
            {
                return(PropertyUtil <T> .CreateTypedProperty("CreatePropertyParseable", type));
            }

            throw Serializer.ThrowNoEncoder(format, type);
        }