Pull to refresh

Comments 23

Expression мощный инструмент, только как он с GC работает? С одной стороны, в .net нет инструментов для выгрузки неиспользуемого кода. Если подгрузил assembly, то и будет в памяти болтаться, а с другой можно динамически создавать Expression, потом их, опять же, динамически компилировать, использовать и забывать (сдавать в GC) и проблем с утечкой памяти вроде как нет.
Как это реализовано поверх MSIL 2.0 для меня осталось загадкой :)
Вот такой вот код:
int s = 0;
for(int i=0;i<int.MaxValue;i++)
{
    int i1 = i;
    Expression<Func<int, int>> x = j => j + i1;
    Func<int, int> f = x.Compile();
    s += f(i);
    if (i % 100 == 0)
    {
        Console.WriteLine(s);
        GC.Collect();
    }
}
Console.WriteLine(s);


стабильно держится на 15 мегабайтах и не растет уже минут 10. А как сделано — тут я пас.
В Expression идет значение i1 или i1 идет как замыкание? Если как замыкание, то возможно используется кэширование.
i1 замыкается, но каждый цикл замыкается новая переменная, так что вроде все честно.
Вот такое изменение вашего кода поможет вам понять, как это сделано:

Assembly [] b = AppDomain.CurrentDomain.GetAssemblies();
Console.WriteLine(«Before = » + b.Length);

int s = 0;
for (int i = 0; i < int.MaxValue; i++)
{
  int i1 = i;
   Expression<Func<int, int>> x = j => j + i1;
   Func<int, int> f = x.Compile();

   Assembly[] a = AppDomain.CurrentDomain.GetAssemblies();
   Console.WriteLine(«After = » + a.Length);

   s += f(i);
   if (i % 100 == 0)
   {
     Console.WriteLine(s);
     GC.Collect();
   }
}
Как это нету возможности? В .net есть возможность выгружать динамически код — создаете Assembly, вгружаете в нее то, что надо, отрабатывает, выгружаете весь домен
… Виноват, описАлся — «создаете Assembly» следует читать как «создаете AppDomain»
вот, вот, и я о том же…
Expressions не в пример проще для создания, нежели Emit
Хорошая техника! Аналогичный подход используется в ASP.NET MVC 2 RC (например ActionMethodDispatcher.cs)
аналогичный подход используется когда SQL запросы надо оптимизировать. Смотришь как делает LINQ2SQL, разбираешься почему именно так(если надо) и делаешь на основе этого новый запрос, но с учетом твоей логике.
Только не говорите, что это очень крутая штука для создания своего ORM =)

Кстати, кому интересно, недавно рылся в блогах MSDN и нашел некого meek'а. У него крутая статья по
деревьям выражений

Кто-то же делает ORM, ведь «не на деревьях растут» :)
У нас используется генерация asp страниц из xml — там используется рефлекшн, думаем перейти на expressions.
Интересно с каких пор появился оператор methodof?
Эрик Липерт писал, что такого оператора у нас не будет даже в C# 4 — слишком дорого проектировать, тестировать, сопровождать (((
Оператора нет, а IL вызов есть. Именно такой код показывает Reflector.
Да, знаю. Просто очень жаль, что нет такого оператора в C#.
А смысл иметь оператор methodof? Сделайте свой статический класс хелпер со статическим методов methodof(Type type, String method_name, BindingAttributes attr) и юзайте на здоровье. Если же считаете, что оператор будет работать быстрее такого метода (типа нативная поддержка, как typeof), то возникает вопрос: зачем выигрышь в 10 микросекунд? Или Вы собираетесь миллион раз вызывать этот оператор? (что какбы редко бывает и не стоит делать)
Смысл — в строгой типизации. Если бы был оператор methodof, то, например, при рефакторинге я бы не заботился о том, что надо еще поменять имена функций в строковых константах. Поэтому, например, я предпочитаю использовать вот такой вот метод:
private static string GetMethodName<T>(Expression<Action<T>> action)
{
	Expression body = action.Body;
	var mce = body as MethodCallExpression;
	if (mce != null)
		return mce.Method.Name;
	return null;
}

Который потом вызывается, например, так:
string beginMethodName = GetMethodName<Stream>(s => s.Read(null, 0, 0));
ExpressionTrees — крутая штука =)
Чешутся руки что-нибудь сделать с помощью них, а работа все время отнимает…
Sign up to leave a comment.

Articles