Example #1
0
        /// <summary>
        /// Implementation of object>expando
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="deep"></param>
        /// <param name="ignoreAttributes"></param>
        /// <returns></returns>
        private static T ToNewExpando <T>(object source, bool deep, IEnumerable <Type> ignoreAttributes) where T : IDynamicMetaObjectProvider, IDictionary <string, object>, new()
        {
            if (source == null)
            {
                return(default(T));
            }
            HashSet <Type> IgnoreList = new HashSet <Type>(ignoreAttributes);

            if (source is string && Objects.IsJson(source))
            {
                source = Utility.JSON.ParseJSON((string)source);
            }

            if (Objects.IsExpando(source))
            {
                return((T)Objects.CloneObject(source, deep));
            }
            else if (source is IDictionary)
            {
                T           dict       = new T();
                IDictionary sourceDict = (IDictionary)source;
                IDictionary itemDict   = (IDictionary)source;
                foreach (var key in itemDict.Keys)
                {
                    string stringKey = key.ToString();
                    if (dict.ContainsKey(stringKey))
                    {
                        throw new InvalidCastException("The key '" + key + "' could not be added because the same key already exists. Conversion of the source object's keys to strings did not result in unique keys.");
                    }
                    dict.Add(stringKey, itemDict[key]);
                }
                return((T)dict);
            }
            else if (!source.IsExtendableType())
            {
                throw new InvalidCastException("Conversion to ExpandObject must be from a JSON string, an object, or an ExpandoObject");
            }

            T target = new T();
            IDictionary <string, object> targetDict = (IDictionary <string, object>)target;

            IEnumerable <MemberInfo> members = source.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance);

            foreach (var member in members)
            {
                if (!IgnorePropertyNames.Contains(member.Name))
                {
                    foreach (object attrObj in member.GetCustomAttributes(false))
                    {
                        Attribute attr = (Attribute)attrObj;
                        if (IgnoreList.Contains(attr.GetType()))
                        {
                            goto NextAttribute;
                        }
                    }
                    string name = member.Name;


                    object value = null;
                    bool   skip  = false;

                    if (member is PropertyInfo)
                    {
                        PropertyInfo propInfo = (PropertyInfo)member;
                        if (propInfo.GetIndexParameters().Length == 0 &&
                            propInfo.CanRead)
                        {
                            // wrap this because we are testing every single property - if it doesn't work we don't want to use it
                            try
                            {
                                value = ((PropertyInfo)member).GetGetMethod().Invoke(source, null);
                            }
                            catch
                            {
                                skip = true;
                            }
                        }
                    }
                    else if (member is FieldInfo)
                    {
                        value = ((FieldInfo)member).GetValue(source);
                    }
                    else
                    {
                        continue;
                    }
                    if (!skip)
                    {
                        targetDict[name] = deep ? Objects.CloneObject(value, true) : value;
                    }
                }
                NextAttribute : { }
            }

            return(target);
        }