От: | Serginio1 | https://habrahabr.ru/users/serginio1/topics/ | |
Дата: | 28.04.16 12:06 | ||
Оценка: |
Вот код нашего нового создателя:
class ExpressionCreator<T> : ICreator<T>
{
private readonly Func<Dictionary<string, object>, T> _creator;
public ExpressionCreator()
{
var type = typeof(T);
var newExpression = Expression.New(type);
var dictParam = Expression.Parameter(typeof(Dictionary<string, object>), "d");
var list = new List<MemberBinding>();
var propertyInfos = type.GetProperties(BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.SetProperty);
foreach (var propertyInfo in propertyInfos)
{
Expression call = Expression.Call(
typeof (DictionaryExtension),
"GetValue", new[] {propertyInfo.PropertyType},
new Expression[]
{
dictParam,
Expression.Constant(propertyInfo.Name)
});
MemberBinding mb = Expression.Bind(propertyInfo.GetSetMethod(), call);
list.Add(mb);
}
var ex = Expression.Lambda<Func<Dictionary<string, object>, T>>(
Expression.MemberInit(newExpression, list),
new[] {dictParam});
_creator = ex.Compile();
}
public T Create(Dictionary<string, object> props)
{
return _creator(props);
}
}
* This source code was highlighted with Source Code Highlighter.
Мы, фактически, повторяем код, созданный компилятором, но динамически обрабатываем все свойства любого данного объекта. (Построение полностью аналогично разобранному выше).
Новый создатель создается 0,01 секунду (что в 10 раз медленнее, чем у reflection, но конструктор вызывается только один раз) и тратит 0,017 секунд на создание 10000 объектов (что в 70 раз быстрее).
Кстати, если создавать объект Foo напрямую
internal class DirectCreator : ICreator<Foo>
{
public Foo Create(Dictionary<string, object> props)
{
return new Foo
{
Name = props.GetValue<string>("Name"),
Value = props.GetValue<int>("Value")
};
}
}
то это получается всего в два раза быстрее, чем через expressions.
Вот такие штуки позволяют нам делать Expression trees.