Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Optimised ObjectToDictionary using dynamic methods

  • Loading branch information...
commit 1a361807b1f3af911cc3f8eedfdba6a818abe3ea 1 parent e3248bd
@markrendle authored
View
29 Simple.Data.Mocking/XmlMockAdapter.cs
@@ -5,9 +5,6 @@
namespace Simple.Data.Mocking
{
- using System.Collections;
- using Extensions;
-
public class XmlMockAdapter : Adapter, IAdapterWithRelation
{
private readonly Lazy<XElement> _data;
@@ -194,31 +191,5 @@ private IEnumerable<string> GetKeyFieldNames(string tableName)
if (keyAttribute == null) return Enumerable.Empty<string>();
return keyAttribute.Value.Split(',');
}
-
- private static object ObjectToDictionary(object obj)
- {
- var dynamicRecord = obj as SimpleRecord;
- if (dynamicRecord != null)
- {
- return new Dictionary<string, object>(dynamicRecord, HomogenizedEqualityComparer.DefaultInstance);
- }
-
- var dictionary = obj as IDictionary<string, object>;
- if (dictionary != null)
- {
- return dictionary;
- }
-
- var list = obj as IEnumerable;
- if (list != null)
- {
- var originals = list.Cast<object>().ToList();
- var dictionaries = originals.Select(o => ObjectToDictionary(o) as IDictionary<string, object>).Where(o => o != null && o.Count > 0).ToList();
- if (originals.Count == dictionaries.Count)
- return dictionaries;
- }
-
- return obj.ObjectToDictionary();
- }
}
}
View
39 Simple.Data/ConcreteCollectionTypeCreator.cs
@@ -1,21 +1,18 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Collections;
-using System.Dynamic;
-using System.Linq.Expressions;
-
namespace Simple.Data
{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Linq;
+
internal static class ConcreteCollectionTypeCreator
{
private static readonly List<Creator> _creators = new List<Creator>
- {
- new GenericSetCreator(),
- new GenericListCreator(),
- new NonGenericListCreator()
- };
+ {
+ new GenericSetCreator(),
+ new GenericListCreator(),
+ new NonGenericListCreator()
+ };
public static bool IsCollectionType(Type type)
{
@@ -85,10 +82,10 @@ private static bool ConvertEnum(Type type, object value, out object result)
{
if (value is string)
{
- result = Enum.Parse(type, (string) value);
+ result = Enum.Parse(type, (string)value);
return true;
}
-
+
result = Enum.ToObject(type, value);
return true;
}
@@ -103,10 +100,10 @@ protected bool TryConvertElements(Type type, IEnumerable items, out Array result
list = items.OfType<object>().ToList();
var array = Array.CreateInstance(type, list.Count);
- for(var i = 0; i < array.Length; i++)
+ for (var i = 0; i < array.Length; i++)
{
object element;
- if(!TryConvertElement(type, list[i], out element))
+ if (!TryConvertElement(type, list[i], out element))
return false;
array.SetValue(element, i);
}
@@ -124,9 +121,9 @@ public override bool IsCollectionType(Type type)
return false;
return type == typeof(IEnumerable) ||
- type == typeof(ICollection) ||
- type == typeof(IList) ||
- type == typeof(ArrayList);
+ type == typeof(ICollection) ||
+ type == typeof(IList) ||
+ type == typeof(ArrayList);
}
public override bool TryCreate(Type type, IEnumerable items, out object result)
@@ -147,7 +144,7 @@ public override bool IsCollectionType(Type type)
return false;
var genericTypeDef = type.GetGenericTypeDefinition();
- if(genericTypeDef.GetGenericArguments().Length != 1)
+ if (genericTypeDef.GetGenericArguments().Length != 1)
return false;
return genericTypeDef == typeof(IEnumerable<>) ||
View
44 Simple.Data/Extensions/ObjectEx.cs
@@ -5,16 +5,50 @@
namespace Simple.Data.Extensions
{
+ using System.Collections.Concurrent;
+ using System.Linq.Expressions;
+ using System.Reflection;
+
public static class ObjectEx
{
+ private static readonly ConcurrentDictionary<Type, Func<object, IDictionary<string, object>>> Converters =
+ new ConcurrentDictionary<Type, Func<object, IDictionary<string, object>>>();
+
public static IDictionary<string, object> ObjectToDictionary(this object obj)
{
if (obj == null) return new Dictionary<string, object>();
- return (from property in obj.GetType().GetProperties()
- select
- new KeyValuePair<string, object>(property.Name,
- property.GetValue(obj, null)))
- .ToDictionary();
+
+ return Converters.GetOrAdd(obj.GetType(), MakeToDictionaryFunc)(obj);
+ }
+
+ private static Func<object, IDictionary<string, object>> MakeToDictionaryFunc(Type type)
+ {
+ var param = Expression.Parameter(typeof(object));
+ var typed = Expression.Variable(type);
+ var newDict = Expression.New(typeof(Dictionary<string, object>));
+ var listInit = Expression.ListInit(newDict, GetElementInitsForType(type, typed));
+
+ var block = Expression.Block(new[] { typed },
+ Expression.Assign(typed, Expression.Convert(param, type)),
+ listInit);
+
+ return Expression.Lambda<Func<object, IDictionary<String, object>>>(block, param).Compile();
+ }
+
+ static readonly MethodInfo DictionaryAddMethod = typeof(Dictionary<string, object>).GetMethod("Add");
+
+ static IEnumerable<ElementInit> GetElementInitsForType(Type type, Expression param)
+ {
+ return type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
+ .Where(p => p.CanRead)
+ .Select(p => PropertyToElementInit(p, param));
+ }
+
+ static ElementInit PropertyToElementInit(PropertyInfo propertyInfo, Expression instance)
+ {
+ return Expression.ElementInit(DictionaryAddMethod,
+ Expression.Constant(propertyInfo.Name),
+ Expression.Convert(Expression.Property(instance, propertyInfo), typeof(object)));
}
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.