You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Version Used:
VisualStudio.17.Release/17.12.3+35527.113
Microsoft .NET Framework
Version 4.8.09037
C# Tools 4.12.0-3.24572.7+dfa7fc6bdea31a858a402168384192b633c811fa
There are two (related?) issues
unexpected created code for lambda containing this
unexpected result of SemanticModel.AnalyzeDataFlow
Description
I was wondering why c# creates a display class to capture this when it could just not do it.
My proposal for that (dotnet/csharplang#8914) was met with a comment claiming it already does what i wished for. That turned out to be true, sometimes. The compiler uses a display class for a lambda that does not need it, if the same scope also contains a lambda that needs it. That is issue 1).Example code is provided below as sharplab.io-links.
I encountered issue 2) when i tried to update a ClrHeap-Analyzer (https://github.com/sonnemaf/RoslynClrHeapAllocationAnalyzer) to not show warnings for cases when no display class is created. The source of the warnings from that analyzer is, that SemanticModel.AnalyzeDataFlow claims that a ParenthesizedLambdaExpressionSyntax with no local capture requires one even if it does not.
An example is provided as an uploaded solution.
Issue 1: Code Examples Display Class Creation
Example 1: if both the lamba and the local function only require the capture of this, they are created as member method and no display_class is created.
Example 2: If one lambda requires capture of a stack variable through a display_class, even the cases where the display_class is not required are created as members of the display_class
// Built 27.12.2024
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
string code = @"using System;
private sealed class ThisCaptureTwo
{
void TestFunction(int parameter)
{
// Make sure the lambda that does not require capturing is in its own scope
{
var action1 = new System.Action(() =>
{
this.TestFunction(66);
});
}
// Make sure the lambda that DOES require capturing is in its own scope
{
int localVariable = 5;
var action2 = new System.Action(() =>
{
this.TestFunction(localVariable);
});
}
}
}
";
SyntaxTree tree = CSharpSyntaxTree.ParseText(code);
// Create a Compilation
var compilation = CSharpCompilation.Create("MyCompilation",
syntaxTrees: [tree],
references: [MetadataReference.CreateFromFile(typeof(object).Assembly.Location)]);
// Get the Semantic Model
var semanticModel = compilation.GetSemanticModel(tree);
SyntaxNode root = tree.GetRoot();
var lambdaExpressionSyntaxes = root.DescendantNodes().OfType<ParenthesizedLambdaExpressionSyntax>().ToList();
ParenthesizedLambdaExpressionSyntax lambdaexpNoVariable = lambdaExpressionSyntaxes[0];
var dataFlowAnalysis1 = semanticModel.AnalyzeDataFlow(lambdaexpNoVariable);
Console.WriteLine("-- CODE -------------------------------------------------");
Console.WriteLine(code);
Console.WriteLine("-- LAMBDA -------------------------------------------------");
Console.WriteLine(lambdaexpNoVariable.ToFullString());
Console.WriteLine("DataFlow Analysis Captured: " + dataFlowAnalysis1.Captured.Length);
for (int i = 0; i < dataFlowAnalysis1.Captured.Length; i++)
{
Console.WriteLine($"{i} {dataFlowAnalysis1.Captured[i].Name}");
}
ParenthesizedLambdaExpressionSyntax lambdaexpWithLocalVariable = lambdaExpressionSyntaxes[1];
var dataFlowAnalysis2 = semanticModel.AnalyzeDataFlow(lambdaexpWithLocalVariable);
Console.WriteLine("-- LAMBDA -------------------------------------------------");
Console.WriteLine(lambdaexpWithLocalVariable.ToFullString());
Console.WriteLine("DataFlow Analysis Captured: " + dataFlowAnalysis2.Captured.Length);
for (int i = 0; i < dataFlowAnalysis2.Captured.Length; i++)
{
Console.WriteLine($"{i} {dataFlowAnalysis2.Captured[i].Name}");
}
Console.ReadKey(true);
I believe @jaredpar has covered this in the past. Precise tracking has pros/cons. So we've opted for a simpler model which results in simpler display class layout and allocations, at the cost of this sort of thing happening in some cases.
Version Used:
VisualStudio.17.Release/17.12.3+35527.113
Microsoft .NET Framework
Version 4.8.09037
C# Tools 4.12.0-3.24572.7+dfa7fc6bdea31a858a402168384192b633c811fa
There are two (related?) issues
Description
I was wondering why c# creates a display class to capture this when it could just not do it.
My proposal for that (dotnet/csharplang#8914) was met with a comment claiming it already does what i wished for. That turned out to be true, sometimes. The compiler uses a display class for a lambda that does not need it, if the same scope also contains a lambda that needs it. That is issue 1).Example code is provided below as sharplab.io-links.
I encountered issue 2) when i tried to update a ClrHeap-Analyzer (https://github.com/sonnemaf/RoslynClrHeapAllocationAnalyzer) to not show warnings for cases when no display class is created. The source of the warnings from that analyzer is, that SemanticModel.AnalyzeDataFlow claims that a ParenthesizedLambdaExpressionSyntax with no local capture requires one even if it does not.
An example is provided as an uploaded solution.
Issue 1: Code Examples Display Class Creation
Example 1: if both the lamba and the local function only require the capture of this, they are created as member method and no display_class is created.
https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA+ABATARgLABQGADAAQY4oDchJ5OAdADICWAdgI41FkUMAqMBABdudCgFZuhNgEMAtjADOAB1lgYpAMIQ2SiABsYAQRUr8BAN6FSt0u2Ewocg+Sz0A7DbvWCd/6QwAG4wbML07gDybACiIWEAErJmoewA5twBdt5ZGCikALIw8sBOGBLCLLoAFADKwlDppLJQaQCUOQG+Wbk4AJzVACQARACqSsqkalAKpJYtaQC+zWwAJvZ6wrJsGqSrsltzwgAWLEoCEPWNbGnVbYvDbdJ+PYuEnf4A9J+kMQgKKiMpBwIFIADkIHszoDZABPNykMCwA4wVYMD52PKkRxKYR3DG2bo9L4/ABqTiUVTYwNBTAUwFk2OOB1IsA4AFcWLAlEyzgAaUjAdnhMDbQWaVa6TQAdxYJwgwqhqgMcLcBICJzODGicVCwiSKTYTQA1ABeUh3UimgB86v8ROJWU15yKJTKFSp1WGtQgik1N0CBgmpGZhtRAEJHplHbZFtGY+8XjHvqRyVBKbpSFhQQARCCTNgQcJszmwZpKmHwgBm7J2lV06KTjud2ti8X1yRUqQDZtITAgooM5XrbHjjqx/cHw89HSbxIdMbsLddpSg05q3t9MH9aRDndCEajdrsbznJ86p9PQA
Example 2: If one lambda requires capture of a stack variable through a display_class, even the cases where the display_class is not required are created as members of the display_class
https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA+ABATARgLABQGADAAQY4oDchJ5OAdADICWAdgI41FkUMAqMBABdudCgFZuhNgEMAtjADOAB1lgYpAMIQ2SiABsYAQRUr8BAN6FSt0u2Ewocg+Sz0A7DbvWCd/6QwAG4wbML07gDybACiIWEAErJmoewA5twBdt5ZGCikALIw8sBOGBLCLLoAFADKwlDppLJQaQCUOQG+Wbk4AJzVACQARACqSsqkalAKpJYtaQC+zWwAJvZ6wrJsGqSrsltzwgAWLEoCEPWNbGnVbYvDbdJ+PYuEnf4A9J+kMQgKKiMpCwIFIABEzoDZABPNykMCwA4wdbBUKkABm0FIJ006IArjtKrolHsIKQ2BBwoiDAZYWwYMj7MIAPwfOx5bHKYR3Nm2bo9L4/ABqTiUVTYpBwoKYCmAsmxxwOpFgHDxLFgJJOZwANKRgHjwpA8QZ1qVSfTSAB3FgnCAGvaQgwwty8gJa87ROKhYRJFJsJoAagAvKQ7qQgwA+V3+fkCrLuhhFEplCri6rDWoQRRam6BAwTUiKv3IgCEj0ycdsiwrlfeL0r31IIqgYt0wNBYIgkwpVJgqvVmnlq0dzvxhPFDGjdgTnviPuSKlSueDpCYEDAsgM5SJbBrcY5a43W9TNQ69bjscr09O5yTpSg27TGazMBzaULC9CpfLU6rv9I/6Ns2rYSgAzB2XYkiqaqwAqmgbiowh4rBEDoqQShbGAADWpBBC0LCyMARiAT82zrCceJQX2MGTEOI6wtgGJYji8IGBASjITA/4OM04akFI/4zrEc6+ou/rLiGYaRv+l5XrYCZ3imO7ppm2anLmIRQLCMD5poRZid+pABs0FxXOkdxPP+1aum8562bZQA=
Issue 2: Project that shows result of SemanticModel.AnalyzeDataFlow
RoslynFlowCaptureTest.zip
Sourcecode:
Console Output:
The text was updated successfully, but these errors were encountered: