/// <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); }