Roslyn 通用方法专业化主体
Roslyn generic method specialization body
是否有可能在调用期间为特定于具体类型的泛型方法获取操作 and/or 语法节点?所以在下面的示例中它将是 string
而不是 T
?
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Semantics;
using System;
using System.Linq;
namespace so
{
internal class Walker : CSharpSyntaxWalker
{
public SemanticModel Model { get; set; }
public override void VisitAssignmentExpression(AssignmentExpressionSyntax node)
{
var operation = (IAssignmentExpression)Model.GetOperation(node);
if (operation.Value.Kind == OperationKind.InvocationExpression)
{
var invocation = (IInvocationExpression)operation.Value;
foreach (
var syntax in
invocation.TargetMethod.DeclaringSyntaxReferences.Select(
x => (MethodDeclarationSyntax)x.GetSyntax()))
{
var e = (TypeOfExpressionSyntax)syntax.ExpressionBody.Expression;
Console.WriteLine($"Generic type {invocation.TargetMethod.TypeParameters.First()} specialized with {invocation.TargetMethod.TypeArguments.First()}");
// How to get specialized body here? Currently it is just generic TypeParameters
var symbol = Model.GetSymbolInfo(e.Type).Symbol;
var typeofOperation = (ITypeOfExpression)Model.GetOperation(e);
Console.WriteLine($"{syntax.Identifier.Text} {symbol} {typeofOperation.TypeOperand}");
}
}
base.VisitAssignmentExpression(node);
}
}
internal static class Program
{
private static void Main()
{
var tree = CSharpSyntaxTree.ParseText(@"
public class Program
{
static Type TypeOf<T>() => typeof(T);
public static void Main()
{
Type t;
t = TypeOf<string>();
}
}");
var mscorlib = MetadataReference.CreateFromFile(typeof(object).Assembly.Location);
var compilation = CSharpCompilation.Create(null, new[] { tree }, new[] { mscorlib });
var walker = new Walker { Model = compilation.GetSemanticModel(tree) };
walker.Visit(tree.GetRoot());
}
}
}
输出:
Generic type T specialized with string
TypeOf T T
我正在尝试在输出中获得 TypeOf string string
。
代码 github - https://github.com/isanych/so-39447605
你不能(直接)这样做。
通用类型替换发生在调用点,而不是声明。没有语法树将您的方法体替换为 T
.
如果你真的想这样做,你需要手动将 T
替换为来自调用站点的值(并注意各种极端情况,例如名称隐藏、来自 base [= 的类型参数) 18=] 包含 类、重载解析,甚至更糟)。
是否有可能在调用期间为特定于具体类型的泛型方法获取操作 and/or 语法节点?所以在下面的示例中它将是 string
而不是 T
?
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Semantics;
using System;
using System.Linq;
namespace so
{
internal class Walker : CSharpSyntaxWalker
{
public SemanticModel Model { get; set; }
public override void VisitAssignmentExpression(AssignmentExpressionSyntax node)
{
var operation = (IAssignmentExpression)Model.GetOperation(node);
if (operation.Value.Kind == OperationKind.InvocationExpression)
{
var invocation = (IInvocationExpression)operation.Value;
foreach (
var syntax in
invocation.TargetMethod.DeclaringSyntaxReferences.Select(
x => (MethodDeclarationSyntax)x.GetSyntax()))
{
var e = (TypeOfExpressionSyntax)syntax.ExpressionBody.Expression;
Console.WriteLine($"Generic type {invocation.TargetMethod.TypeParameters.First()} specialized with {invocation.TargetMethod.TypeArguments.First()}");
// How to get specialized body here? Currently it is just generic TypeParameters
var symbol = Model.GetSymbolInfo(e.Type).Symbol;
var typeofOperation = (ITypeOfExpression)Model.GetOperation(e);
Console.WriteLine($"{syntax.Identifier.Text} {symbol} {typeofOperation.TypeOperand}");
}
}
base.VisitAssignmentExpression(node);
}
}
internal static class Program
{
private static void Main()
{
var tree = CSharpSyntaxTree.ParseText(@"
public class Program
{
static Type TypeOf<T>() => typeof(T);
public static void Main()
{
Type t;
t = TypeOf<string>();
}
}");
var mscorlib = MetadataReference.CreateFromFile(typeof(object).Assembly.Location);
var compilation = CSharpCompilation.Create(null, new[] { tree }, new[] { mscorlib });
var walker = new Walker { Model = compilation.GetSemanticModel(tree) };
walker.Visit(tree.GetRoot());
}
}
}
输出:
Generic type T specialized with string
TypeOf T T
我正在尝试在输出中获得 TypeOf string string
。
代码 github - https://github.com/isanych/so-39447605
你不能(直接)这样做。
通用类型替换发生在调用点,而不是声明。没有语法树将您的方法体替换为 T
.
如果你真的想这样做,你需要手动将 T
替换为来自调用站点的值(并注意各种极端情况,例如名称隐藏、来自 base [= 的类型参数) 18=] 包含 类、重载解析,甚至更糟)。