/// <summary>
        /// Save an object in the source object's extension dictionary.
        /// </summary>
        /// <typeparam name="T">The type of the object to store.</typeparam>
        /// <param name="source">The source object to write the object to.</param>
        /// <param name="key">A string that acts as the key in the extension dictionary.</param>
        /// <param name="data">The object to store.</param>
        /// <exception cref="System.Exception">Thrown when an AutoCAD error occurs.</exception>
        public static void SaveData <T>(this DBObject source, string key, T data)
        {
            Require.ParameterNotNull(source, nameof(source));

            void saveData(ResultBuffer buffer)
            {
                if (!source.IsWriteEnabled)
                {
                    source.UpgradeOpen();
                }

                if (source.ExtensionDictionary.IsNull)
                {
                    source.CreateExtensionDictionary();
                }

                Helpers.WrapInTransaction(source, tr =>
                {
                    var dict = (DBDictionary)tr.GetObject(source.ExtensionDictionary, OpenMode.ForWrite);

                    if (dict.Contains(key))
                    {
                        var xRecord  = (Xrecord)tr.GetObject(dict.GetAt(key), OpenMode.ForWrite);
                        xRecord.Data = buffer;
                    }
                    else
                    {
                        var xRecord  = new Xrecord();
                        xRecord.Data = buffer;
                        dict.SetAt(key, xRecord);
                        tr.AddNewlyCreatedDBObject(xRecord, true);
                    }
                });
            }

            ResultBuffer getResultBuffer(DxfCode code) => new ResultBuffer(new[] { new TypedValue((int)code, data) });

            // TODO: Add further types

            if (typeof(T) == typeof(bool))
            {
                saveData(getResultBuffer(DxfCode.Bool));
            }
            else if (typeof(T) == typeof(double))
            {
                saveData(getResultBuffer(DxfCode.Real));
            }
            else if (typeof(T) == typeof(byte))
            {
                saveData(getResultBuffer(DxfCode.Int8));
            }
            else if (typeof(T) == typeof(char) ||
                     typeof(T) == typeof(short))
            {
                saveData(getResultBuffer(DxfCode.Int16));
            }
            else if (typeof(T) == typeof(int))
            {
                saveData(getResultBuffer(DxfCode.Int32));
            }
            else if (typeof(T) == typeof(long))
            {
                saveData(getResultBuffer(DxfCode.Int64));
            }
            else if (typeof(T) == typeof(string))
            {
                saveData(getResultBuffer(DxfCode.Text));
            }
            else
            {
                saveData(new ResultBuffer(Helpers.Serialize(data)
                                          .Select(a => new TypedValue((int)DxfCode.BinaryChunk, a))
                                          .ToArray()));
            }
        }
        /// <summary>
        /// Reads an object from the source object's XData.
        /// </summary>
        /// <typeparam name="T">The type of the object to read.</typeparam>
        /// <param name="source">The source object to read the object from.</param>
        /// <param name="regAppName">The name of the RegApp to read the data from.</param>
        /// <exception cref="System.Exception">Thrown when an AutoCAD error occurs.</exception>
        /// <returns>The object in the extension dictionary.</returns>
        private static T GetFromXData <T>(DBObject source, string regAppName)
        {
            var resultBuffer = source.GetXDataForApplication(regAppName);

            Require.ObjectNotNull(resultBuffer, $"RegApp '{regAppName}' not found");

            using (resultBuffer)
            {
                var xData = resultBuffer.Cast <TypedValue>()
                            .Skip(1)
                            .ToArray();

                var targetType = typeof(T);
                var enumerable = typeof(T).GetInterface(typeof(IEnumerable <>).Name);

                if (typeof(T).Equals(typeof(string)))
                {
                    enumerable = null;
                }
                else if (enumerable != null)
                {
                    targetType = enumerable.GenericTypeArguments
                                 .FirstOrDefault();
                }

                var tmpValues = new List <object>();
                CollectValues(xData, tmpValues, targetType);
                var values = tmpValues.ToArray();

                if (values.Length == 1 && values[0] is object[])
                {
                    values = values[0] as object[];
                }

                if (enumerable != null)
                {
                    if (targetType == typeof(object))
                    {
                        return((T)(object)values);
                    }
                    else
                    {
                        var newValues = (IList)Activator.CreateInstance(typeof(List <>).MakeGenericType(targetType));

                        foreach (var value in values)
                        {
                            if (typeof(T).Equals(typeof(Vector3d)))
                            {
                                var tmp = (Point3d)value;
                                newValues.Add(new Vector3d(tmp.X, tmp.Y, tmp.Z));
                            }
                            else
                            {
                                newValues.Add(value);
                            }
                        }

                        return((T)newValues);
                    }
                }
                else if (values.Length == 1)
                {
                    return((T)values[0]);
                }
                else
                {
                    if (typeof(T).Equals(typeof(object)))
                    {
                        return((T)(object)values);
                    }
                    else
                    {
                        throw new Exception("XData contains multiple: " + values.GetType().Name + " cannot be converted to " + typeof(T).Name);
                    }
                }
            }
        }