如何使用 Roslyn 在 C# 中获取 lambda 的类型?
How to get type of lambda in C# using Roslyn?
我正在用 roslyn 编写代码修复程序。我希望它以这种方式工作:
之前:
IEnumerable<int> list = new List<int> {1, 2, 3, 4};
list = list.Where(x => x%2 == 0);
之后:
...
IEnumerable<int> list = new List<int> {1, 2, 3, 4};
list = list.Where(lambdaMethod);
...
private static bool lamdaMethod(int x)
{
return x % 2 == 0;
}
问题是我找不到正确的方法来获取 return 类型的方法和参数类型。
我的分析器模板方法:
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
// TODO: Replace the following code with your own analysis, generating a CodeAction for each fix to suggest
var diagnostic = context.Diagnostics.FirstOrDefault();
var diagnosticSpan = diagnostic.Location.SourceSpan;
// Find the type declaration identified by the diagnostic.
var declaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf()
.OfType<LambdaExpressionSyntax>().FirstOrDefault();
if (declaration == null)
return;
// Register a code action that will invoke the fix.
context.RegisterCodeFix(
CodeAction.Create(
title: $"{"Just Title"}",
createChangedDocument: c => MakeLambdaOptimization(context.Document, declaration, c),
equivalenceKey: nameof(CodeFixResources.CodeFixTitle)),
diagnostic);
}
如您所见,我正在与 LambdaExpressionSyntax
合作。还有 SimpleLambdaExpressionSyntax
和 ParenthesizedLambdaExpressionSyntax
可以帮助我得到 ParameterSyntax
。在 ParameterSyntax
中,我可以找到 Type
,但它是空的,我得到 NullReferenceException。
我试图获得整个类型的 lambda(例如 Func<int, bool>
),我想它会对我有所帮助。我该怎么做?听说过SemanticModel,但是不知道怎么用
您可以使用 SemanticModel.GetSymbolInfo(ExpressionSyntax)
来获取 lambda 符号。从 lambda 符号中您可以找到所需的信息(return 类型和参数类型)。这是一个代码片段(为简单起见,在控制台应用程序而不是代码修复的上下文中编写 - 您将能够让它为代码修复工作):
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
// You don't need to create or get a compilation yourself. I'm creating it manually since I'm in a console app.
CSharpCompilation comp = CSharpCompilation.Create(null, new[] { SyntaxFactory.ParseSyntaxTree("System.Func<int, bool> f = x => x % 2 == 0;") }, new[] { MetadataReference.CreateFromFile(typeof(Func<>).Assembly.Location) });
// You already have the LambdaExpressionSyntax, ignore the following two lines, which again because I'm in a console app.
var root = comp.SyntaxTrees[0].GetRoot();
var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single();
// Here you'll need to get a semantic model via 'await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);'
var model = comp.GetSemanticModel(lambda.SyntaxTree);
// That's the core of what you want to do.
if (model.GetSymbolInfo(lambda).Symbol is IMethodSymbol lambdaSymbol)
{
// prints 'bool'
Console.WriteLine(lambdaSymbol.ReturnType.ToDisplayString());
foreach (var parameter in lambdaSymbol.Parameters)
{
// prints 'int' (loop is entered once since my lambda has a single parameter).
Console.WriteLine(parameter.Type.ToDisplayString());
}
}
我正在用 roslyn 编写代码修复程序。我希望它以这种方式工作:
之前:
IEnumerable<int> list = new List<int> {1, 2, 3, 4};
list = list.Where(x => x%2 == 0);
之后:
...
IEnumerable<int> list = new List<int> {1, 2, 3, 4};
list = list.Where(lambdaMethod);
...
private static bool lamdaMethod(int x)
{
return x % 2 == 0;
}
问题是我找不到正确的方法来获取 return 类型的方法和参数类型。
我的分析器模板方法:
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
// TODO: Replace the following code with your own analysis, generating a CodeAction for each fix to suggest
var diagnostic = context.Diagnostics.FirstOrDefault();
var diagnosticSpan = diagnostic.Location.SourceSpan;
// Find the type declaration identified by the diagnostic.
var declaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf()
.OfType<LambdaExpressionSyntax>().FirstOrDefault();
if (declaration == null)
return;
// Register a code action that will invoke the fix.
context.RegisterCodeFix(
CodeAction.Create(
title: $"{"Just Title"}",
createChangedDocument: c => MakeLambdaOptimization(context.Document, declaration, c),
equivalenceKey: nameof(CodeFixResources.CodeFixTitle)),
diagnostic);
}
如您所见,我正在与 LambdaExpressionSyntax
合作。还有 SimpleLambdaExpressionSyntax
和 ParenthesizedLambdaExpressionSyntax
可以帮助我得到 ParameterSyntax
。在 ParameterSyntax
中,我可以找到 Type
,但它是空的,我得到 NullReferenceException。
我试图获得整个类型的 lambda(例如 Func<int, bool>
),我想它会对我有所帮助。我该怎么做?听说过SemanticModel,但是不知道怎么用
您可以使用 SemanticModel.GetSymbolInfo(ExpressionSyntax)
来获取 lambda 符号。从 lambda 符号中您可以找到所需的信息(return 类型和参数类型)。这是一个代码片段(为简单起见,在控制台应用程序而不是代码修复的上下文中编写 - 您将能够让它为代码修复工作):
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
// You don't need to create or get a compilation yourself. I'm creating it manually since I'm in a console app.
CSharpCompilation comp = CSharpCompilation.Create(null, new[] { SyntaxFactory.ParseSyntaxTree("System.Func<int, bool> f = x => x % 2 == 0;") }, new[] { MetadataReference.CreateFromFile(typeof(Func<>).Assembly.Location) });
// You already have the LambdaExpressionSyntax, ignore the following two lines, which again because I'm in a console app.
var root = comp.SyntaxTrees[0].GetRoot();
var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single();
// Here you'll need to get a semantic model via 'await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);'
var model = comp.GetSemanticModel(lambda.SyntaxTree);
// That's the core of what you want to do.
if (model.GetSymbolInfo(lambda).Symbol is IMethodSymbol lambdaSymbol)
{
// prints 'bool'
Console.WriteLine(lambdaSymbol.ReturnType.ToDisplayString());
foreach (var parameter in lambdaSymbol.Parameters)
{
// prints 'int' (loop is entered once since my lambda has a single parameter).
Console.WriteLine(parameter.Type.ToDisplayString());
}
}