Are Resharper's close warnings correct?
I faced the following situation today
public async Task<Stream> GetApproveDocumentAsync<T>(Guid id, int revision, PdfLayoutType pdfLayoutType, string resourceFilePath, CadDrawingType cadDrawingType, int approvalWidth, int approvalHeight, Action<T> fillModelAction = null) where T : BaseApproveModel, new() {
var previewFileName = $"{id}_{revision}_preview.png";
Stream previewFile;
using (var resourceFileStream = new FileStream(resourceFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true)) {
previewFile = await _cadApiService.ConvertDrawingToImageAsync(resourceFileStream, cadDrawingType, FileFormat.EVD, FileFormat.PNG, approvalWidth, approvalHeight).ConfigureAwait(false);
}
Func<string[], T> createBaseApproveModelFunc = graphicContentFilenames => { //Implicitly captured closure: previewFile
var model = new T {
GraphicContentFiles = graphicContentFilenames,
CadPreview = previewFileName,
Customer = _userService.GetCurrentOverrideCustomer()?.CustomerName
};
fillModelAction?.Invoke(model);
return model;
};
Action<List<StreamWithFileName>> fillGraphicContentAction = currentGraphicContent => { //Implicitly captured closure: fillModelAction, this
currentGraphicContent.Add(new StreamWithFileName {FileName = previewFileName, Stream = previewFile});
};
return await _apagoService.ConstcutPdf(pdfLayoutType, createBaseApproveModelFunc, fillGraphicContentAction).ConfigureAwait(false);
}
I thought I knew how closures work, but I can't figure out the behavior of ReSharper. Is ReSharper replacing these two warnings by mistake (or error)?
I am using ReSharper Ultimate 2016.2.2
source to share
I think what the resolver is saying is that these two closures also grab additional things that your code doesn't think it is using in this lambda. The first closure uses previewFileName
and this
(for the field _userService
), so your capture is clearly intentional, but: it may not be obvious to you that you are also capturing previewFile
. The reason that you capture extra things, is that the area for the captured cells is the same, so the compiler generates one closure to capture all the previewFile
, this
, previewFileName
and fillModelAction
- and a copy of the circuit has two methods - one for Func<string[], T>
and one for Action<List<StreamWithFileName>>
. note thatpreviewFileName
used by both lambdas, so: no warnings.
Understanding this can be important to the reasons for garbage collection - if one lambda lived much longer than the other, you might not want to accidentally save unnecessary things, hence the warning. For example, lambda fillGraphicContentAction
keeps everything this
alive (regardless of this
) even though lambda doesn't use this
.
source to share