如何在Roslyn中基于INamedTypeSymbol构造System.Action<>泛型类型
如何将INamedTypeSymbol包装为System.Action<>泛型类型符号
要在Roslyn中把一个INamedTypeSymbol(比如MyAwesomeApp.Foo)转换为对应的System.Action<MyAwesomeApp.Foo>类型符号,核心是通过编译上下文获取Action的泛型定义,再用目标类型构造具体泛型实例,具体实现如下:
实现步骤
- 获取编译上下文:从目标类型符号的所在程序集拿到
Compilation对象,这是访问系统类型的唯一可靠入口。 - 获取Action的泛型定义:通过元数据名称
System.Action1获取未构造的Action<>`泛型类型符号。 - 构造具体泛型类型:调用泛型定义的
Construct方法,传入目标类型符号,得到最终的Action<T>类型符号。
代码示例
using Microsoft.CodeAnalysis; using System; public static class SymbolExtensions { public static INamedTypeSymbol ToActionOfType(this INamedTypeSymbol targetType) { if (targetType == null) throw new ArgumentNullException(nameof(targetType)); // 获取当前编译环境 Compilation compilation = targetType.ContainingAssembly.Compilation; // 获取System.Action<T>的泛型定义,元数据名称格式为"类型全名`泛型参数数量" INamedTypeSymbol actionGenericDef = compilation.GetTypeByMetadataName("System.Action`1") ?? throw new InvalidOperationException("无法在当前编译环境中找到System.Action<T>类型"); // 构造具体的Action<目标类型> return actionGenericDef.Construct(targetType); } }
关键说明
- 元数据名称规则:泛型类型的元数据名称格式是
类型全名泛型参数数量,比如Action<T1,T2>对应System.Action2,以此类推。 - 编译上下文的必要性:必须通过当前
Compilation获取类型,避免跨编译环境的类型不匹配问题。 - 多参数Action扩展:如果需要构造多参数的
Action,只需修改元数据名称并传入多个类型符号即可,示例:// 获取Action<T1,T2>的泛型定义 INamedTypeSymbol action2GenericDef = compilation.GetTypeByMetadataName("System.Action`2"); // 构造Action<Foo, Bar> INamedTypeSymbol actionOfFooBar = action2GenericDef.Construct(fooTypeSymbol, barTypeSymbol);
内容的提问来源于stack exchange,提问作者Shadow
相关产品推荐
相关产品推荐

