Action / Lambda Expression Memory Управление вопросом - PullRequest
8 голосов
/ 01 июня 2011

Я сохраняю действие в локальной переменной, затем использую после того, как эта локальная переменная выходит из области видимости.Есть ли опасность быть очищенным перед использованием?Вот пример:

public List<object> GetMaps() {
    Action<Customer1, Customer2> baseMap = (Customer1 c1, Customer2 c2) => {
        c2.FirstName = c1.FirstName;
    };

    var list = new List<object>() {
        new Action<SpecialCustomer1 c1, SpecialCustomer2 c2>() {
            baseMap(c1, c2);
            c2.SpecialProperty = c1.SpecialProperty;
        },
        new Action<SpecialCustomer1 c1, SpecialCustomer2 c2>() {
            baseMap(c1, c2);
            c2.SpecialProperty2 = c1.SpecialProperty2;
        },
    };

    return list;
}

Итак, в этом примере вы можете видеть, что функция возвращает список действий, которые вызывают baseMap.baseMap это просто локальная переменная.Достаточно ли того, что он вызывается в других действиях, чтобы .NET знал, что его не нужно очищать?

Ответы [ 4 ]

13 голосов
/ 01 июня 2011

Я отсылаю вас к разделу 5.1.7 спецификации C # 4, в котором говорится:

Если локальная переменная захвачена анонимной функцией, ее время жизни увеличивается как минимум до делегата или выражениядерево, созданное из анонимной функции, наряду с любыми другими объектами, которые ссылаются на захваченную переменную, могут быть использованы для сбора мусора.

Даже если управление проходит конец локальной области, время жизнииз местного продлен.На практике мы делаем это, превращая local в поле класса замыкания, а затем поддерживая класс живым, ссылаясь на него в делегате (или дереве выражений).

Обратите внимание, что вы можете столкнуться с противоположнымпроблема;иногда вещи живут дольше, чем вы хотите:

Expensive expensive = new Expensive();
Cheap cheap = new Cheap();
Action longlived = ()=>M(cheap);
Action shortlived = ()=>M(expensive);

То, как это работает сегодня в C #, - это замыкание, генерируемое для двух делегатов, которое поддерживает как «дешевый», так и «дорогой», пока существуетдолгоживущий делегат, хотя долгоживущий делегат на самом деле не использует «дорогой»!(VB, JScript и многие другие языки, которые имеют замыкания, также имеют эту проблему.)

Что мы могли бы здесь сделать, это обнаружить эту ситуацию в компиляторе и создать два замыкания.Мы рассматриваем возможность сделать это для будущей версии C #.

5 голосов
/ 01 июня 2011

Нет, это не в опасности.Анонимный метод, который использует локальную переменную извне этого анонимного метода, будет скомпилирован в новый класс с полем, которое сохраняет эту локальную переменную, и методом, который соответствует анонимному методу.

В вашем случае это будетсоздайте что-то вроде следующего:

class ModifiedClosure
{
    private Action<Customer1, Customer2> _baseMap;
    public ModifiedClosure(Action<Customer1, Customer2> baseMap)
    {
        _baseMap = baseMap;
    }

    public void Method(SpecialCustomer1 c1, SpecialCustomer2 c2)
    {
        _baseMap(c1, c2);
        c2.SpecialProperty = c1.SpecialProperty;
    }
}

Инициализация списка будет выглядеть примерно так:

Action<Customer1, Customer2> baseMap = (c1, c2) => c2.FirstName = c1.FirstName;

var list = new List<object>()
{
    (Action<SpecialCustomer1, 
            SpecialCustomer2>)(new ModifiedClosure(baseMap).Method),
    // ...
};

КСТАТИ: Ваш синтаксис немного отключен.Создание списка не скомпилируется.Это должно выглядеть так:

var list = new List<object>()
{
    (Action<SpecialCustomer1, SpecialCustomer2>)((c1, c2) =>
    {
        baseMap(c1, c2);
        c2.SpecialProperty = c1.SpecialProperty;
    }),
    (Action<SpecialCustomer1, SpecialCustomer2>)((c1, c2) =>
    {
        baseMap(c1, c2);
        c2.SpecialProperty2 = c1.SpecialProperty2;
    })
};
1 голос
/ 01 июня 2011

Это не выходит за рамки, так как на него ссылается ваш список, поэтому он не будет очищен сборщиком мусора.

Так нет, ты не в опасности

0 голосов
/ 01 июня 2011

Делегат является ссылочным типом и не будет очищен, пока не будет хотя бы одна ссылка на него из root.Поэтому, если вы создадите делегат Action и передадите его из метода, не беспокойтесь об очистке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...