Комментарии 27
На некоторых .Net хостингах Expression использовать не получится, т.к. там не хватает привилегий коду для выполнения. (например не удается заюзать rsdn.data.framework.dll, на паре бесплатных хостингов). А так да, он быстр.
+2
Спасибо, действительно так. Добавлю в минусы к этому способу.
0
Странно, сейчас попытался найти в MSDN про Sercurity по Expression<TDelegate>.Compile, и не нашел.
Если вдруг у кого есть информация, какой именно permission требует, напишите. Логически он должен требовать что-то…
Если вдруг у кого есть информация, какой именно permission требует, напишите. Логически он должен требовать что-то…
0
Спасибо за статью! Давно хотел потестить скорость Expressions, да всё как-то руки не доходили :)
+2
> var instance = Expression.Parameter(typeof(Object), «i»);
>…
вот это извращение.
а так не пробывали?
var expression = (Expression)( x => x > 0 );
и компилятор всё сделает за вас.
>…
вот это извращение.
а так не пробывали?
var expression = (Expression)( x => x > 0 );
и компилятор всё сделает за вас.
-1
в 0) var expression = (Expression)( x => x > 0 ); не скомпилится, так что компилятор за вас ничего не сделает.
в 1) мне кажется вы не читали код, или не поняли что автор хотел сделать.
нужно иметь доступ к полю динамически, т.е. заранее неизвестно поле. напишите ка лямбду не зная значение чего вы хотите прочитать.
в 2) даже если знаете что прочитать заранее, установить значение таким способом не получится.
в 1) мне кажется вы не читали код, или не поняли что автор хотел сделать.
нужно иметь доступ к полю динамически, т.е. заранее неизвестно поле. напишите ка лямбду не зная значение чего вы хотите прочитать.
в 2) даже если знаете что прочитать заранее, установить значение таким способом не получится.
+1
Еще к слову, метод «Компиляция выражений (Expressions)» и «Словарь делегатов», одинаковы. Разница только в скорости доступа к словарю.
Магия цифр:
85,93% — 63,64% = 22,29%
Всё по тому что Expression.Compile() создает динамический метод и вызывает его через делегат. В итоге в обоих случаях получается делегат который вызывает компилированный код.
Магия цифр:
85,93% — 63,64% = 22,29%
Всё по тому что Expression.Compile() создает динамический метод и вызывает его через делегат. В итоге в обоих случаях получается делегат который вызывает компилированный код.
0
Еще можно было рассмотреть вариант, аналогичный последнему, но написанный непосредственно на MSIL'е. Или в четвертом фреймворке Expression — это обертка, чтоб не писать опкоды?
0
А статья хорошая, спасибо.
0
э-э-э. При компиляции экспрешеннов получается MSIL-код. Что в 3.5, что в 4ом FW.
0
Да, это я понял. Я имел в виду, что возможно если сразу писать что-то типа:
то можно сэкономить еще немного времени.
//...
ILGenerator ctorIL = smth.GetILGenerator();
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Call, objCtor);
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Ldarg_1);
ctorIL.Emit(OpCodes.Stfld, xField);
//...
то можно сэкономить еще немного времени.
0
На самом деле это был первый вариант реализации — с использованием DynamicMethod. Даже был более или менее работающий код, но он был довольно громоздкий, и не очень читабелен. А про производительности по сравнению с Expressions он давал разницу сравнимую с random (фактически автоматический генератор иногда генерирует непонятные конструкции по типа безусловных прыжков на следующую инструкцию). По этому я удалил это решение.
Возможно все-таки надо было включить, но статья и так вышла слегка раздутая, хотелось чтоб различия в методах были все-таки более заметные. А то реально можно придумать еще парочку модификаций каждого метода :)
Возможно все-таки надо было включить, но статья и так вышла слегка раздутая, хотелось чтоб различия в методах были все-таки более заметные. А то реально можно придумать еще парочку модификаций каждого метода :)
+1
Отличная статья, приятный стиль изложения. Но проверьте пожалуйста текст на орфографию — очень режет глаза в некоторых местах: «по этому» например. Думаю вы просто спешили, когда набирали — ничего страшного со всеми случается :)
+1
Я бы еще при компиляции деревьев выражений убрал приведение типа. Пусть был бы тип делегата Func<StaticObject, T>.
Без приведения с проверкой будет работать быстрее.
Без приведения с проверкой будет работать быстрее.
+1
Действительно так, но я хотел метод с выражениями максимально приблизить к рефлексии. PropertyInfo.GetValue тоже принимает Object как первый параметр.
0
В реальной системе метод «Динамический объект с перехватом вызова» фактически сведется к методу Рефлексии т.к. в перехватчике TryMember надо будет на основе рефлексии определять что дергать.
Метод с ExpandoObject мало пригодный для разработки объектов с динамическими методами и свойстваи т.к. код динамических методов надо назначать экземплярам в рантайме, это неудобно. (или я не правильно понял идею ExpandoObject ?)
В разрабтываемой платформе с динамической типизацией мы сейчас используем рефлексию с кешированием. Классы разрабатываются программистами как статические, а динамические свойста и методы размечаются атрибута, данные для рефлексии кешируются.
После перехода на .net 4.0 планируем перейти на метод «Динамический объект со статическим контейнером», это действительно дает большой прирост производительности в сравнении с рефлексией
Метод с ExpandoObject мало пригодный для разработки объектов с динамическими методами и свойстваи т.к. код динамических методов надо назначать экземплярам в рантайме, это неудобно. (или я не правильно понял идею ExpandoObject ?)
В разрабтываемой платформе с динамической типизацией мы сейчас используем рефлексию с кешированием. Классы разрабатываются программистами как статические, а динамические свойста и методы размечаются атрибута, данные для рефлексии кешируются.
После перехода на .net 4.0 планируем перейти на метод «Динамический объект со статическим контейнером», это действительно дает большой прирост производительности в сравнении с рефлексией
0
В реальной системе перехватом можно пользоваться для совсем не существующих методов. Например: есть веб-узел, предоставляющий свои функции через урл по типу domain.com/{funcname}/{parameters}
С помощью перехвата это можно сделать реализовав один перехватчик кидающий запрос на узел. В результате будет что-то вроде service.DoSomeFunc(a,b) будет кидать запрос на domain/DoSomeFunc/a=xxx&b=xxx
С ExpandoObject — действительно он лучше всего предназначен для представления сильно отличающихся друг от друга сущностей. Иначе стоит задуматься о создании общих классов с необходимыми функциями и делегировать им поведение.
Если сравнивать с рефлексией, то метод с выражениями меня лично очень поразил — ведь фактически особых изменений нет — вместо PropertyInfo/MethodInfo храним откомпилированное выражение. А прирос производительности просто потрясающий.
С помощью перехвата это можно сделать реализовав один перехватчик кидающий запрос на узел. В результате будет что-то вроде service.DoSomeFunc(a,b) будет кидать запрос на domain/DoSomeFunc/a=xxx&b=xxx
С ExpandoObject — действительно он лучше всего предназначен для представления сильно отличающихся друг от друга сущностей. Иначе стоит задуматься о создании общих классов с необходимыми функциями и делегировать им поведение.
Если сравнивать с рефлексией, то метод с выражениями меня лично очень поразил — ведь фактически особых изменений нет — вместо PropertyInfo/MethodInfo храним откомпилированное выражение. А прирос производительности просто потрясающий.
0
А как будет выглядить вызов методово в случае с методом на основе Expressions?
0
Т.е. если вместо свойства (property) — метод? тогда просто вместо Expression.Property — Expression.Call. А остальное то же самое — в конце концов выходит обычный Func<>, который можно вызывать, и по скорости намного выше MethodInfo.Invoke
Кстати, если говорить именно о 4.0, я там заметил RuntimeVariablesExpression — возможно его можно было бы использовать, но пока не нашел достаточно информации.
Кстати, если говорить именно о 4.0, я там заметил RuntimeVariablesExpression — возможно его можно было бы использовать, но пока не нашел достаточно информации.
0
leo, чисто ради интереса написал вот такой метод:
public static Action MakeCall<TClass, TArg>(TClass instance, string name)
{
var instanceExpr = Expression.Constant(instance);
var param = Expression.Parameter(typeof (TArg), "arg");
var call = Expression.Call(instanceExpr, name, Type.EmptyTypes, param);
var expr = Expression.Lambda<Action>(call,param).Compile();
return expr;
}
использовать:
0
сорри, случайно отправилось.
теперь вместо
Можно
разница (пустой класс б с 1 методом, фор с вызовом 20000000 раз через expr и через method.Invoke(b, «xxx»); ):
time = 00:00:00.8665175
time = 00:00:27.2921866
впечатляет… :)
теперь вместо
var method = typeof (B).GetMethod("DoWork");
method.Invoke(b, "xxx");
Можно
var b = new B();
var expr = MakeCall<B,string>(b, "DoWork");
expr("xxx");
разница (пустой класс б с 1 методом, фор с вызовом 20000000 раз через expr и через method.Invoke(b, «xxx»); ):
time = 00:00:00.8665175
time = 00:00:27.2921866
впечатляет… :)
0
Большое спасибо за подробный анализ, очень познавательно, только:
РЕФЛЕКСИЯ, -и; ж. [от лат. reflexio — обращение назад] Книжн. Размышление о своих чувствах, анализ своих переживаний. Предаваться рефлексии. Обнаружить склонность к рефлексии. //Осмысление чего-л., размышление над чем-л. Р. пьесы. Р. над языковым материалом.
Всё-таки в данном контексте «reflection» — это «отражение».
РЕФЛЕКСИЯ, -и; ж. [от лат. reflexio — обращение назад] Книжн. Размышление о своих чувствах, анализ своих переживаний. Предаваться рефлексии. Обнаружить склонность к рефлексии. //Осмысление чего-л., размышление над чем-л. Р. пьесы. Р. над языковым материалом.
Всё-таки в данном контексте «reflection» — это «отражение».
0
Когда я писал, у меня тоже возник этот вопрос. На википедии было три варианта: «отражение или рефлексия (синоним интроспекция, англ. reflection)». Я выбрал «рефлексия», потому-что оно проще чем «интроспекция» но более ближе к английскому варианту «reflection».
Но, действительно, в дальнейшем я все-таки пересмотрю свою точку зрения. Спасибо.
Но, действительно, в дальнейшем я все-таки пересмотрю свою точку зрения. Спасибо.
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Динамические вызовы: сравнение методов