/// <summary>
 /// Constructor
 /// </summary>
 /// <param name="atr">Attribute</param>
 /// <param name="fi">Field</param>
 public BinarySerializerCacheEntry(BinaryPropertyAttribute atr, FieldInfo fi) : this(atr, fi.FieldType)
 {
     Name     = fi.Name;
     GetValue = fi.GetValue;
     SetValue = fi.SetValue;
     ReadOnly = false;
 }
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="atr">Attribute</param>
 /// <param name="pi">Property</param>
 public BinarySerializerCacheEntry(BinaryPropertyAttribute atr, PropertyInfo pi) : this(atr, pi.PropertyType)
 {
     Name     = pi.Name;
     GetValue = pi.GetValue;
     SetValue = pi.SetValue;
     ReadOnly = !pi.CanWrite;
 }
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="atr">Attribute</param>
        /// <param name="btype">Type</param>
        private BinarySerializerCacheEntry(BinaryPropertyAttribute atr, Type btype)
        {
            var type    = btype;
            var isArray = type.IsArray;
            var isList  = _iListType.IsAssignableFrom(type);

            MaxLength = atr == null ? 0 : atr.MaxLength;

            if (type == typeof(byte[]))
            {
                ReadValue  = GetByteArrayValue;
                WriteValue = SetByteArrayValue;
            }
            else
            {
                if (isArray || isList)
                {
                    // Extract type of array
                    type = type.GetElementType();
                }

                if (type.IsEnum)
                {
                    type = Enum.GetUnderlyingType(type);
                }

                if (type == typeof(string))
                {
                    ReadValue  = GetStringValue;
                    WriteValue = SetStringValue;
                }
                else if (type == typeof(long))
                {
                    ReadValue  = GetInt64Value;
                    WriteValue = SetInt64Value;
                }
                else if (type == typeof(ulong))
                {
                    ReadValue  = GetUInt64Value;
                    WriteValue = SetUInt64Value;
                }
                else if (type == typeof(int))
                {
                    ReadValue  = GetInt32Value;
                    WriteValue = SetInt32Value;
                }
                else if (type == typeof(uint))
                {
                    ReadValue  = GetUInt32Value;
                    WriteValue = SetUInt32Value;
                }
                else if (type == typeof(short))
                {
                    ReadValue  = GetInt16Value;
                    WriteValue = SetInt16Value;
                }
                else if (type == typeof(ushort))
                {
                    ReadValue  = GetUInt16Value;
                    WriteValue = SetUInt16Value;
                }
                else if (type == typeof(byte))
                {
                    ReadValue  = GetByteValue;
                    WriteValue = SetByteValue;
                }
                else if (type == typeof(sbyte))
                {
                    ReadValue  = GetSByteValue;
                    WriteValue = SetSByteValue;
                }
                else if (type == typeof(bool))
                {
                    ReadValue  = GetBoolValue;
                    WriteValue = SetBoolValue;
                }
                else if (type == typeof(double))
                {
                    ReadValue  = GetDoubleValue;
                    WriteValue = SetDoubleValue;
                }
                else if (!TryRecursive(type, out ReadValue, out WriteValue))
                {
                    throw new NotImplementedException();
                }

                if (isArray)
                {
                    var ar = new ArrayType(btype, MaxLength, ReadValue, WriteValue);
                    ReadValue  = ar.GetArrayValue;
                    WriteValue = ar.SetArrayValue;
                }
                else if (isList)
                {
                    var ls = new ListType(btype, MaxLength, ReadValue, WriteValue);
                    ReadValue  = ls.GetListValue;
                    WriteValue = ls.SetListValue;
                }
            }
        }
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="atr">Attribute</param>
        /// <param name="type">Type</param>
        /// <param name="member">Member</param>
        public BinarySerializerCacheEntry(BinaryPropertyAttribute atr, Type type, MemberInfo member)
        {
            Type = type;
            Name = member.Name ?? null;

            var isArray        = type.IsArray;
            var isList         = _iListType.IsAssignableFrom(type);
            var isReadOnlyList = type.IsGenericType && _iReadonlyListType.Contains(type.GetGenericTypeDefinition());
            var isHashSet      = type.IsGenericType && _iHashSetType.Contains(type.GetGenericTypeDefinition());
            var isDic          = type.IsGenericType && _iDictionaryTypes.Contains(type.GetGenericTypeDefinition());

            if (atr == null)
            {
                Context           = null;
                MaxLength         = Order = 0;
                Override          = false;
                ValueHandlerLogic = ValueHandlerLogicType.Writable;
            }
            else
            {
                Override          = atr.Override;
                Context           = atr;
                MaxLength         = atr.MaxLength;
                Order             = atr.Order;
                ValueHandlerLogic = atr.ValueHandlerLogic;
            }

            if (type == typeof(byte[]))
            {
                Serializer = new BinaryByteArraySerializer(MaxLength);
            }
            else
            {
                if (isArray || isList)
                {
                    // Extract type of array

                    type = type.GetElementType();
                }
                else
                {
                    if (isHashSet || isReadOnlyList)
                    {
                        // Extract type of generic type

                        type = type.GetGenericArguments().FirstOrDefault();
                    }
                    else
                    {
                        if (isDic)
                        {
                            // Is dictionary

                            var gen = type.GetGenericArguments();

                            if (!TryRecursive(member, gen[0], out var key, MaxLength) ||
                                !TryRecursive(member, gen[1], out var value, MaxLength))
                            {
                                throw new NotImplementedException();
                            }

                            Serializer = new BinaryDictionarySerializer(type, gen[0], key, gen[1], value, MaxLength);
                            return;
                        }
                    }
                }

                var isEnum = type.IsEnum;

                if (isEnum)
                {
                    type = Enum.GetUnderlyingType(type);
                }

                // Try to extract the BinarySerializer

                if (!TryRecursive(member, type, out Serializer, MaxLength))
                {
                    throw new NotImplementedException();
                }

                if (isArray)
                {
                    Serializer = new BinaryArraySerializer(Type, Serializer, MaxLength);
                }
                else if (isList)
                {
                    Serializer = new BinaryListSerializer(Type, Serializer, MaxLength);
                }
                else if (isReadOnlyList)
                {
                    Serializer = new BinaryReadOnlyListSerializer(Type, Serializer, MaxLength);
                }
                else if (isHashSet)
                {
                    Serializer = new BinaryHashSetSerializer(Type, Serializer, MaxLength);
                }
                else if (isEnum)
                {
                    Serializer = new BinaryEnumSerializer(Type, Serializer);
                }

                if (Serializer == null)
                {
                    throw new NotImplementedException();
                }
            }
        }
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="atr">Attribute</param>
 /// <param name="fi">Field</param>
 public BinarySerializerCacheEntry(BinaryPropertyAttribute atr, FieldInfo fi) : this(atr, fi.FieldType, fi)
 {
     GetValue = fi.GetValue;
     SetValue = fi.SetValue;
 }
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="atr">Attribute</param>
 /// <param name="pi">Property</param>
 public BinarySerializerCacheEntry(BinaryPropertyAttribute atr, PropertyInfo pi) : this(atr, pi.PropertyType, pi)
 {
     GetValue = pi.GetValue;
     SetValue = pi.SetValue;
 }