У меня есть следующий код:
public double CalculateDailyProjectPullForceMax(DateTime date, string start = null, string end = null)
{
Log("Calculating Daily Pull Force Max...");
var pullForceList = start == null
? _pullForce.Where((t, i) => _date[i] == date).ToList() // implicitly captured closure: end, start
: _pullForce.Where(
(t, i) => _date[i] == date && DateTime.Compare(_time[i], DateTime.Parse(start)) > 0 &&
DateTime.Compare(_time[i], DateTime.Parse(end)) < 0).ToList();
_pullForceDailyMax = Math.Round(pullForceList.Max(), 2, MidpointRounding.AwayFromZero);
return _pullForceDailyMax;
}
Теперь я добавил комментарий к строке, что ReSharper предлагает изменение. Что это значит или зачем это нужно менять?implicitly captured closure: end, start
Ответы:
Предупреждение говорит вам, что переменные
end
иstart
остаются в живых, как и любые лямбды внутри этого метода остаются в живых.Взгляните на короткий пример
Я получаю предупреждение «Неявно захваченное закрытие: g» при первой лямбде. Это говорит мне, что
g
нельзя собирать мусор, пока используется первая лямбда.Компилятор генерирует класс для обоих лямбда-выражений и помещает в него все переменные, которые используются в лямбда-выражениях.
Так что в моем примере
g
иi
проводятся в одном классе для выполнения моих делегатов. Еслиg
это тяжелый объект с большим количеством оставленных ресурсов, сборщик мусора не смог его восстановить, поскольку ссылка в этом классе все еще жива, пока используется любое из лямбда-выражений. Так что это потенциальная утечка памяти, и это является причиной предупреждения R #.@splintor Как и в C #, анонимные методы всегда хранятся в одном классе на метод, есть два способа избежать этого:
Используйте метод экземпляра вместо анонимного.
Разделите создание лямбда-выражений на два метода.
источник
Random
экземпляр.Договорились с Питером Мортенсеном.
Компилятор C # генерирует только один тип, который инкапсулирует все переменные для всех лямбда-выражений в методе.
Например, учитывая исходный код:
Компилятор генерирует тип выглядит так:
И
Capture
метод компилируется как:Хотя вторая лямбда не использует
x
, она не может быть собрана сборщиком мусора, так какx
компилируется как свойство сгенерированного класса, используемого в лямбда.источник
Предупреждение является действительным и отображается в методах, которые имеют более одной лямбды , и они захватывают разные значения .
Когда вызывается метод, содержащий лямбда-выражения, объект, сгенерированный компилятором, создается с помощью:
Например:
Изучите сгенерированный код для этого класса (немного прибрано):
Обратите внимание на экземпляр
LambdaHelper
созданных магазиновp1
иp2
.Представьте себе, что:
callable1
держит долгосрочную ссылку на свой аргумент,helper.Lambda1
callable2
не сохраняет ссылку на свой аргумент,helper.Lambda2
В этой ситуации ссылка
helper.Lambda1
также косвенно ссылается на строку вp2
, а это означает, что сборщик мусора не сможет ее освободить. В худшем случае это утечка памяти / ресурсов. В качестве альтернативы, он может поддерживать объект (ы) дольше, чем необходимо, что может оказать влияние на GC, если они будут повышены с gen0 до gen1.источник
p1
объект,callable2
подобный следующему:callable2(() => { p2.ToString(); });
- не вызовет ли это все еще ту же проблему (сборщик мусора не сможет ее освободить), котораяLambdaHelper
будет по-прежнему содержатьсяp1
иp2
?LambdaHelper
выше) для всех лямбд в родительском методе. Таким образом, даже еслиcallable2
он не используетсяp1
, он будет использовать один и тот же объект захватаcallable1
, и этот объект захвата будет ссылаться как на, такp1
и наp2
. Обратите внимание, что это действительно имеет значение только для ссылочных типов, иp1
в этом примере это тип значения.Для запросов Linq to Sql вы можете получить это предупреждение. Область действия лямбды может пережить метод из-за того, что запрос часто актуализируется после того, как метод выходит из области видимости. В зависимости от вашей ситуации вы можете захотеть актуализировать результаты (т. Е. Через .ToList ()) внутри метода, чтобы разрешить GC для экземпляров метода, захваченных в лямбда-выражении L2S.
источник
Вы всегда можете разобраться с причинами предложений R #, просто нажав на подсказки, как показано ниже:
Этот намек направит вас сюда .
источник