/// <summary>
 /// Get length in bytes from a valuetype or AdsSerializable
 /// </summary>
 /// <typeparam name="T">ValueType or AdsSerializable</typeparam>
 /// <returns></returns>
 public static uint GetByteLengthFromType <T>(uint defaultStringLength)
 {
     if (typeof(IConvertible).IsAssignableFrom(typeof(T)))
     {
         var length = GetByteLengthFromConvertibleType(typeof(T), defaultStringLength);
         if (length == 0)
         {
             throw new AdsException(String.Format("Function GetByteLengthFromType doesn't support this type ({0}) yet!", typeof(T).Name));
         }
         return(length);
     }
     else
     {
         if (AdsAttribute.IsAdsSerializable <T>())
         {
             uint length = 0;
             List <AdsAttribute> attributes = GetAdsAttributes(typeof(T), defaultStringLength);
             attributes.ForEach(a => length += a.ByteSize);
             return(length);
         }
         else
         {
             throw new AdsException(String.Format(TypeNotImplementedError, typeof(T).Name));
         }
     }
 }
        /// <summary>
        /// Convert ValueType or AdsSerializable to byte array
        /// </summary>
        /// <typeparam name="T">ValueType or AdsSerializable</typeparam>
        /// <param name="varValue2">The value that needs conversion</param>
        /// <returns></returns>
        public static IEnumerable <byte> GetBytesFromType <T>(T varValue, uint defaultStringLength)
        {
            List <byte> varValueBytes = null;

            if (typeof(IConvertible).IsAssignableFrom(typeof(T)))
            {
                varValueBytes = GetBytesFromConvertible(typeof(T), varValue as IConvertible, defaultStringLength).ToList();
            }
            else
            {
                if (AdsAttribute.IsAdsSerializable <T>())
                {
                    var totallength = GetByteLengthFromType <T>(defaultStringLength);
                    varValueBytes = new List <byte>((int)totallength);
                    List <AdsAttribute> attributes = GetAdsAttributes(typeof(T), defaultStringLength);
                    foreach (var attr in attributes)
                    {
                        var type  = attr.GetPropery().PropertyType;
                        var val   = attr.GetPropery().GetValue(varValue, null) as IConvertible;
                        var bytes = GetBytesFromConvertible(type, val, defaultStringLength);
                        if (bytes.Count() != attr.ByteSize)
                        {
                            if (bytes.Count() > attr.ByteSize)
                            {
                                bytes = bytes.Take((int)attr.ByteSize).ToList();
                            }
                        }
                        varValueBytes.AddRange(bytes);
                    }
                }
            }

            if (varValueBytes == null)
            {
                throw new AdsException("Function GetBytesFromType doesn't support this type yet!");
            }

            return(varValueBytes);
        }
        /// <summary>
        /// Convert byte array to generic valuetype or AdsSerializable
        /// </summary>
        /// <typeparam name="T">ValueType or AdsSerializable</typeparam>
        /// <param name="value"></param>
        /// <returns></returns>
        public static T GetResultFromBytes <T>(byte[] value, uint defaultStringLength)
        {
            if (typeof(IConvertible).IsAssignableFrom(typeof(T)))
            {
                object v = GetBytesFromConvertibleType(typeof(T), value);
                if (v == null)
                {
                    throw new AdsException("Function GetResultFromBytes doesn't support this type yet!");
                }
                return((T)Convert.ChangeType(v, Type.GetTypeCode(typeof(T)), null));
            }
            else
            {
                if (AdsAttribute.IsAdsSerializable <T>())
                {
                    var adsObj = (T)Activator.CreateInstance(typeof(T));
                    List <AdsAttribute> attributes = GetAdsAttributes(typeof(T), defaultStringLength);

                    uint pos = 0;
                    foreach (var attr in attributes)
                    {
                        byte[] valarray = new byte[attr.ByteSize];
                        Array.Copy(value, (int)pos, valarray, 0, (int)attr.ByteSize);
                        var    type = attr.GetPropery().PropertyType;
                        object val  = GetBytesFromConvertibleType(type, valarray);
                        attr.GetPropery().SetValue(adsObj, val, null);
                        pos += attr.ByteSize;
                    }

                    return(adsObj);
                }
                else
                {
                    throw new AdsException(String.Format(TypeNotImplementedError, typeof(T).Name));
                }
            }
        }
        public static List <AdsAttribute> GetAdsAttributes(Type type, uint defaultStringLength)
        {
            List <AdsAttribute> attributes = new List <AdsAttribute>();

            var props = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

            foreach (var p in props)
            {
                AdsAttribute attr = AdsAttribute.GetAdsAttribute(p);
                if (attr != null)
                {
                    attr.SetProperty(p);
                    if (attr.ByteSize == 0)
                    {
                        attr.ByteSize = GetByteLengthFromConvertibleType(p.PropertyType, defaultStringLength);
                    }
                    attributes.Add(attr);
                }
            }

            attributes = attributes.OrderBy(a => a.Order).ToList();

            return(attributes);
        }