|
11 | 11 | //
|
12 | 12 |
|
13 | 13 | using System;
|
| 14 | +using System.Collections.Concurrent; |
14 | 15 | using System.Collections.Generic;
|
15 | 16 | using System.ComponentModel;
|
16 | 17 | using System.Linq;
|
@@ -706,10 +707,11 @@ public static PropertyInfo[] OnlySerializableProperties(this PropertyInfo[] prop
|
706 | 707 | // else return those properties that are not decorated with IgnoreDataMember
|
707 | 708 | return readableProperties
|
708 | 709 | .Where(prop => prop.AllAttributes()
|
709 |
| - .All(attr => { |
710 |
| - var name = attr.GetType().Name; |
711 |
| - return !IgnoreAttributesNamed.Contains(name); |
712 |
| - })) |
| 710 | + .All(attr => |
| 711 | + { |
| 712 | + var name = attr.GetType().Name; |
| 713 | + return !IgnoreAttributesNamed.Contains(name); |
| 714 | + })) |
713 | 715 | .Where(prop => !JsConfig.ExcludeTypes.Contains(prop.PropertyType))
|
714 | 716 | .ToArray();
|
715 | 717 | }
|
@@ -1223,7 +1225,7 @@ public static List<Attribute> GetAttributes(this PropertyInfo propertyInfo, Type
|
1223 | 1225 | List<Attribute> propertyAttrs;
|
1224 | 1226 | return !propertyAttributesMap.TryGetValue(propertyInfo.UniqueKey(), out propertyAttrs)
|
1225 | 1227 | ? new List<Attribute>()
|
1226 |
| - : propertyAttrs.Where(x => attrType.IsInstanceOf(x.GetType()) ).ToList(); |
| 1228 | + : propertyAttrs.Where(x => attrType.IsInstanceOf(x.GetType())).ToList(); |
1227 | 1229 | }
|
1228 | 1230 |
|
1229 | 1231 | public static object[] AllAttributes(this PropertyInfo propertyInfo)
|
@@ -1766,27 +1768,144 @@ public static Type GetCollectionType(this Type type)
|
1766 | 1768 | return type.ElementType() ?? type.GetTypeGenericArguments().FirstOrDefault();
|
1767 | 1769 | }
|
1768 | 1770 |
|
1769 |
| - public static Dictionary<string, object> ToObjectDictionary<T>(this T obj) |
| 1771 | + private static readonly ConcurrentDictionary<Type, ObjectDictionaryDefinition> toObjectMapCache = |
| 1772 | + new ConcurrentDictionary<Type, ObjectDictionaryDefinition>(); |
| 1773 | + |
| 1774 | + internal class ObjectDictionaryDefinition |
| 1775 | + { |
| 1776 | + public Type Type; |
| 1777 | + public readonly List<ObjectDictionaryFieldDefinition> Fields = new List<ObjectDictionaryFieldDefinition>(); |
| 1778 | + public readonly Dictionary<string, ObjectDictionaryFieldDefinition> FieldsMap = new Dictionary<string, ObjectDictionaryFieldDefinition>(); |
| 1779 | + |
| 1780 | + public void Add(string name, ObjectDictionaryFieldDefinition fieldDef) |
| 1781 | + { |
| 1782 | + Fields.Add(fieldDef); |
| 1783 | + FieldsMap[name] = fieldDef; |
| 1784 | + } |
| 1785 | + } |
| 1786 | + |
| 1787 | + internal class ObjectDictionaryFieldDefinition |
| 1788 | + { |
| 1789 | + public string Name; |
| 1790 | + public Type Type; |
| 1791 | + |
| 1792 | + public PropertyGetterDelegate GetValueFn; |
| 1793 | + public PropertySetterDelegate SetValueFn; |
| 1794 | + |
| 1795 | + public Type ConvertType; |
| 1796 | + public PropertyGetterDelegate ConvertValueFn; |
| 1797 | + |
| 1798 | + public void SetValue(object instance, object value) |
| 1799 | + { |
| 1800 | + if (SetValueFn == null) |
| 1801 | + return; |
| 1802 | + |
| 1803 | + if (!Type.IsInstanceOfType(value)) |
| 1804 | + { |
| 1805 | + lock (this) |
| 1806 | + { |
| 1807 | + //Only caches object converter used on first use |
| 1808 | + if (ConvertType == null) |
| 1809 | + { |
| 1810 | + ConvertType = value.GetType(); |
| 1811 | + ConvertValueFn = TypeConverter.CreateTypeConverter(ConvertType, Type); |
| 1812 | + } |
| 1813 | + } |
| 1814 | + |
| 1815 | + if (ConvertType.IsInstanceOfType(value)) |
| 1816 | + { |
| 1817 | + value = ConvertValueFn(value); |
| 1818 | + } |
| 1819 | + else |
| 1820 | + { |
| 1821 | + var tempConvertFn = TypeConverter.CreateTypeConverter(value.GetType(), Type); |
| 1822 | + value = tempConvertFn(value); |
| 1823 | + } |
| 1824 | + } |
| 1825 | + |
| 1826 | + SetValueFn(instance, value); |
| 1827 | + } |
| 1828 | + } |
| 1829 | + |
| 1830 | + public static Dictionary<string, object> ToObjectDictionary(this object obj) |
1770 | 1831 | {
|
| 1832 | + if (obj == null) |
| 1833 | + return null; |
| 1834 | + |
1771 | 1835 | var alreadyDict = obj as Dictionary<string, object>;
|
1772 | 1836 | if (alreadyDict != null)
|
1773 | 1837 | return alreadyDict;
|
1774 | 1838 |
|
| 1839 | + var type = obj.GetType(); |
| 1840 | + |
| 1841 | + ObjectDictionaryDefinition def; |
| 1842 | + if (!toObjectMapCache.TryGetValue(type, out def)) |
| 1843 | + toObjectMapCache[type] = def = CreateObjectDictionaryDefinition(type); |
| 1844 | + |
1775 | 1845 | var dict = new Dictionary<string, object>();
|
1776 |
| - |
1777 |
| - foreach (var pi in obj.GetType().GetSerializableProperties()) |
| 1846 | + |
| 1847 | + foreach (var fieldDef in def.Fields) |
1778 | 1848 | {
|
1779 |
| - dict[pi.Name] = pi.GetValue(obj, null); |
| 1849 | + dict[fieldDef.Name] = fieldDef.GetValueFn(obj); |
| 1850 | + } |
| 1851 | + |
| 1852 | + return dict; |
| 1853 | + } |
| 1854 | + |
| 1855 | + public static object FromObjectDictionary(this Dictionary<string, object> values, Type type) |
| 1856 | + { |
| 1857 | + var alreadyDict = type == typeof(Dictionary<string, object>); |
| 1858 | + if (alreadyDict) |
| 1859 | + return alreadyDict; |
| 1860 | + |
| 1861 | + ObjectDictionaryDefinition def; |
| 1862 | + if (!toObjectMapCache.TryGetValue(type, out def)) |
| 1863 | + toObjectMapCache[type] = def = CreateObjectDictionaryDefinition(type); |
| 1864 | + |
| 1865 | + var to = type.CreateInstance(); |
| 1866 | + foreach (var entry in values) |
| 1867 | + { |
| 1868 | + ObjectDictionaryFieldDefinition fieldDef; |
| 1869 | + if (!def.FieldsMap.TryGetValue(entry.Key, out fieldDef) || entry.Value == null) |
| 1870 | + continue; |
| 1871 | + |
| 1872 | + fieldDef.SetValue(to, entry.Value); |
| 1873 | + } |
| 1874 | + return to; |
| 1875 | + } |
| 1876 | + |
| 1877 | + private static ObjectDictionaryDefinition CreateObjectDictionaryDefinition(Type type) |
| 1878 | + { |
| 1879 | + var def = new ObjectDictionaryDefinition |
| 1880 | + { |
| 1881 | + Type = type, |
| 1882 | + }; |
| 1883 | + |
| 1884 | + foreach (var pi in type.GetSerializableProperties()) |
| 1885 | + { |
| 1886 | + def.Add(pi.Name, new ObjectDictionaryFieldDefinition |
| 1887 | + { |
| 1888 | + Name = pi.Name, |
| 1889 | + Type = pi.PropertyType, |
| 1890 | + GetValueFn = pi.GetPropertyGetterFn(), |
| 1891 | + SetValueFn = pi.GetPropertySetterFn(), |
| 1892 | + }); |
1780 | 1893 | }
|
1781 | 1894 |
|
1782 | 1895 | if (JsConfig.IncludePublicFields)
|
1783 | 1896 | {
|
1784 |
| - foreach (var fi in obj.GetType().GetSerializableFields()) |
| 1897 | + foreach (var fi in type.GetSerializableFields()) |
1785 | 1898 | {
|
1786 |
| - dict[fi.Name] = fi.GetValue(obj); |
| 1899 | + def.Add(fi.Name, new ObjectDictionaryFieldDefinition |
| 1900 | + { |
| 1901 | + Name = fi.Name, |
| 1902 | + Type = fi.FieldType, |
| 1903 | + GetValueFn = fi.GetFieldGetterFn(), |
| 1904 | + SetValueFn = fi.GetFieldSetterFn(), |
| 1905 | + }); |
1787 | 1906 | }
|
1788 | 1907 | }
|
1789 |
| - return dict; |
| 1908 | + return def; |
1790 | 1909 | }
|
1791 | 1910 | }
|
1792 | 1911 |
|
|
0 commit comments