Roslyn中AllInterfaces对List<>和Dictionary<>返回空值问题求助
在Roslyn源代码生成器中判断成员是否为IEnumerable或IDictionary类型
你的代码里List<>和Dictionary<>的类型接口为空,核心原因是编译时缺少对应程序集的引用:数组的相关接口定义在基础核心程序集(如System.Private.CoreLib)中,所以能正常获取;但List
解决方案步骤
1. 补充必要的程序集引用
创建Compilation时,需要添加包含List
var compilation = CSharpCompilation.Create("RoslynSample") .AddReferences( MetadataReference.CreateFromFile(typeof(object).Assembly.Location), MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location), // 添加List<T>所在的程序集 MetadataReference.CreateFromFile(typeof(List<>).Assembly.Location), // 添加Dictionary<TKey, TValue>所在的程序集 MetadataReference.CreateFromFile(typeof(Dictionary<,>).Assembly.Location)) .AddSyntaxTrees(syntaxTree);
2. 准确判断类型是否实现目标接口
仅遍历AllInterfaces不够灵活,推荐用SymbolEqualityComparer.Default对比符号,覆盖非泛型和泛型版本的接口判断:
private static bool IsEnumerableOrDictionary(ITypeSymbol typeSymbol) { // 获取目标接口的元数据符号 var enumerableType = typeSymbol.Compilation.GetTypeByMetadataName("System.Collections.IEnumerable"); var genericEnumerableType = typeSymbol.Compilation.GetTypeByMetadataName("System.Collections.Generic.IEnumerable`1"); var dictionaryType = typeSymbol.Compilation.GetTypeByMetadataName("System.Collections.IDictionary"); var genericDictionaryType = typeSymbol.Compilation.GetTypeByMetadataName("System.Collections.Generic.IDictionary`2"); if (enumerableType == null || genericEnumerableType == null || dictionaryType == null || genericDictionaryType == null) return false; // 检查当前类型是否直接/间接实现目标接口 return typeSymbol.AllInterfaces.Any(i => SymbolEqualityComparer.Default.Equals(i, enumerableType) || SymbolEqualityComparer.Default.Equals(i.ConstructedFrom, genericEnumerableType) || SymbolEqualityComparer.Default.Equals(i, dictionaryType) || SymbolEqualityComparer.Default.Equals(i.ConstructedFrom, genericDictionaryType)); }
在遍历属性时调用该方法验证:
foreach (var property in properties) { Console.WriteLine($"Property: {property.Name}, Type: {property.Type}"); bool isTargetType = IsEnumerableOrDictionary(property.Type); Console.WriteLine($" Is IEnumerable/IDictionary: {isTargetType}"); // 打印所有接口(验证引用修复后的效果) var allInterfaces = property.Type.AllInterfaces; foreach (var interfaceSymbol in allInterfaces) { Console.WriteLine($" Interface: {interfaceSymbol.ToDisplayString()}"); } }
关键说明
- 使用
SymbolEqualityComparer.Default是Roslyn中对比类型符号的标准方式,可避免泛型实例化导致的对比错误。 - 数组类型本身实现了IEnumerable和IEnumerable
,修复引用后也会被正确识别。
内容的提问来源于stack exchange,提问作者Jim W
相关产品推荐
相关产品推荐

