命名空间详解
简介
本文档详细介绍 INamespaceSymbol(命名空间符号),包括命名空间层次结构、成员访问和全局命名空间处理。
适合人群: 初级到中级开发者
预计阅读时间: 30 分钟
前置知识: 语法树基础、符号系统
📋 本文导航
| 章节 | 难度 | 阅读时间 | 链接 |
|---|---|---|---|
| 核心属性 | 🟢 | 8 分钟 | 查看 |
| 命名空间层次结构 | 🟢 | 10 分钟 | 查看 |
| 命名空间成员访问 | 🟢 | 8 分钟 | 查看 |
| 全局命名空间处理 | 🟢 | 4 分钟 | 查看 |
🟢 核心属性
INamespaceSymbol 表示命名空间,用于组织和管理代码结构。
基本信息属性
csharp
INamespaceSymbol namespaceSymbol;
// 命名空间名称
string name = namespaceSymbol.Name;
// 完整的命名空间名称(包括父命名空间)
string fullName = namespaceSymbol.ToDisplayString();
// 是否是全局命名空间
bool isGlobal = namespaceSymbol.IsGlobalNamespace;
// 父命名空间
INamespaceSymbol containingNamespace = namespaceSymbol.ContainingNamespace;
// 命名空间种类(始终是 Namespace)
SymbolKind kind = namespaceSymbol.Kind; // SymbolKind.Namespace成员访问属性
csharp
// 获取所有成员(包括类型和子命名空间)
ImmutableArray<ISymbol> allMembers = namespaceSymbol.GetMembers();
// 按名称获取成员
ImmutableArray<ISymbol> membersByName = namespaceSymbol.GetMembers("ClassName");
// 获取所有子命名空间
ImmutableArray<INamespaceSymbol> childNamespaces = namespaceSymbol.GetNamespaceMembers();
// 获取所有类型成员
ImmutableArray<INamedTypeSymbol> typeMembers = namespaceSymbol.GetTypeMembers();
// 按名称获取类型成员
ImmutableArray<INamedTypeSymbol> typeMembersByName = namespaceSymbol.GetTypeMembers("ClassName");示例:分析命名空间基本信息
csharp
public void AnalyzeNamespaceBasicInfo(INamespaceSymbol namespaceSymbol)
{
Console.WriteLine($"命名空间名称: {namespaceSymbol.Name}");
Console.WriteLine($"完整名称: {namespaceSymbol.ToDisplayString()}");
Console.WriteLine($"是否是全局命名空间: {namespaceSymbol.IsGlobalNamespace}");
// 显示父命名空间
if (namespaceSymbol.ContainingNamespace != null &&
!namespaceSymbol.ContainingNamespace.IsGlobalNamespace)
{
Console.WriteLine($"父命名空间: {namespaceSymbol.ContainingNamespace.ToDisplayString()}");
}
// 统计成员
var childNamespaces = namespaceSymbol.GetNamespaceMembers();
var types = namespaceSymbol.GetTypeMembers();
Console.WriteLine($"\n成员统计:");
Console.WriteLine($" 子命名空间数量: {childNamespaces.Length}");
Console.WriteLine($" 类型数量: {types.Length}");
// 列出所有类型
if (types.Length > 0)
{
Console.WriteLine("\n类型列表:");
foreach (var type in types)
{
Console.WriteLine($" - {type.TypeKind}: {type.Name}");
}
}
}提示
使用 ToDisplayString() 获取命名空间的完整路径,如 "System.Collections.Generic"。
🟢 命名空间层次结构
命名空间形成树状层次结构,从全局命名空间开始。
遍历命名空间层次
csharp
/// <summary>
/// 获取命名空间的完整路径(从根到当前命名空间)
/// </summary>
public List<INamespaceSymbol> GetNamespacePath(INamespaceSymbol namespaceSymbol)
{
var path = new List<INamespaceSymbol>();
var current = namespaceSymbol;
while (current != null && !current.IsGlobalNamespace)
{
path.Insert(0, current);
current = current.ContainingNamespace;
}
return path;
}
/// <summary>
/// 显示命名空间路径
/// </summary>
public void DisplayNamespacePath(INamespaceSymbol namespaceSymbol)
{
var path = GetNamespacePath(namespaceSymbol);
Console.WriteLine("命名空间路径:");
for (int i = 0; i < path.Count; i++)
{
var indent = new string(' ', i * 2);
Console.WriteLine($"{indent}{path[i].Name}");
}
}递归遍历所有子命名空间
csharp
/// <summary>
/// 递归遍历所有子命名空间
/// </summary>
public void TraverseNamespaces(INamespaceSymbol namespaceSymbol, int level = 0)
{
var indent = new string(' ', level * 2);
if (!namespaceSymbol.IsGlobalNamespace)
{
Console.WriteLine($"{indent}命名空间: {namespaceSymbol.Name}");
}
else
{
Console.WriteLine($"{indent}[全局命名空间]");
}
// 显示类型成员
var types = namespaceSymbol.GetTypeMembers();
if (types.Length > 0)
{
foreach (var type in types)
{
Console.WriteLine($"{indent} 类型: {type.Name} ({type.TypeKind})");
}
}
// 递归遍历子命名空间
var childNamespaces = namespaceSymbol.GetNamespaceMembers();
foreach (var child in childNamespaces)
{
TraverseNamespaces(child, level + 1);
}
}查找特定命名空间
csharp
/// <summary>
/// 在命名空间树中查找特定命名空间
/// </summary>
public INamespaceSymbol FindNamespace(
INamespaceSymbol rootNamespace,
string namespaceName)
{
// 分割命名空间路径
var parts = namespaceName.Split('.');
var current = rootNamespace;
foreach (var part in parts)
{
// 在当前命名空间中查找子命名空间
var childNamespaces = current.GetNamespaceMembers();
current = childNamespaces.FirstOrDefault(ns => ns.Name == part);
if (current == null)
{
return null; // 未找到
}
}
return current;
}
// 使用示例
public void Example(Compilation compilation)
{
var globalNamespace = compilation.GlobalNamespace;
// 查找 System.Collections.Generic 命名空间
var systemNs = FindNamespace(globalNamespace, "System");
if (systemNs != null)
{
var collectionsNs = FindNamespace(systemNs, "Collections");
if (collectionsNs != null)
{
var genericNs = FindNamespace(collectionsNs, "Generic");
if (genericNs != null)
{
Console.WriteLine($"找到命名空间: {genericNs.ToDisplayString()}");
}
}
}
}点击查看完整示例:命名空间树可视化
csharp
/// <summary>
/// 命名空间树可视化工具
/// </summary>
public class NamespaceTreeVisualizer
{
private readonly StringBuilder _output = new StringBuilder();
public string Visualize(INamespaceSymbol rootNamespace)
{
_output.Clear();
_output.AppendLine("命名空间树结构:");
_output.AppendLine("================");
VisualizeNamespace(rootNamespace, "", true);
return _output.ToString();
}
private void VisualizeNamespace(
INamespaceSymbol namespaceSymbol,
string prefix,
bool isLast)
{
// 绘制当前命名空间
var connector = isLast ? "└── " : "├── ";
var name = namespaceSymbol.IsGlobalNamespace
? "[全局命名空间]"
: namespaceSymbol.Name;
_output.AppendLine($"{prefix}{connector}{name}");
// 准备子项的前缀
var childPrefix = prefix + (isLast ? " " : "│ ");
// 获取所有成员
var childNamespaces = namespaceSymbol.GetNamespaceMembers().ToList();
var types = namespaceSymbol.GetTypeMembers().ToList();
// 绘制类型成员
for (int i = 0; i < types.Count; i++)
{
var type = types[i];
var isLastType = (i == types.Count - 1) && (childNamespaces.Count == 0);
var typeConnector = isLastType ? "└── " : "├── ";
_output.AppendLine(
$"{childPrefix}{typeConnector}[{type.TypeKind}] {type.Name}");
}
// 递归绘制子命名空间
for (int i = 0; i < childNamespaces.Count; i++)
{
var child = childNamespaces[i];
var isLastChild = (i == childNamespaces.Count - 1);
VisualizeNamespace(child, childPrefix, isLastChild);
}
}
}
// 使用示例
public void VisualizeExample(Compilation compilation)
{
var visualizer = new NamespaceTreeVisualizer();
var tree = visualizer.Visualize(compilation.GlobalNamespace);
Console.WriteLine(tree);
}
/* 输出示例:
命名空间树结构:
================
└── [全局命名空间]
├── System
│ ├── [Class] Object
│ ├── [Class] String
│ └── Collections
│ └── Generic
│ ├── [Class] List
│ └── [Interface] IEnumerable
└── MyApp
├── [Class] Program
└── Services
└── [Class] UserService
*/关键要点:
- 使用递归遍历命名空间树
- 使用 ASCII 字符绘制树状结构
- 区分命名空间和类型成员
- 正确处理最后一个子项的连接符
🟢 命名空间成员访问
命名空间可以包含类型和子命名空间。
获取类型成员
csharp
/// <summary>
/// 获取命名空间中的所有类型
/// </summary>
public void GetAllTypes(INamespaceSymbol namespaceSymbol)
{
var types = namespaceSymbol.GetTypeMembers();
Console.WriteLine($"命名空间 {namespaceSymbol.ToDisplayString()} 中的类型:");
foreach (var type in types)
{
Console.WriteLine($" {type.TypeKind}: {type.Name}");
// 显示类型的访问修饰符
Console.WriteLine($" 访问修饰符: {type.DeclaredAccessibility}");
// 显示类型的特性
if (type.IsAbstract)
Console.WriteLine(" 特性: 抽象");
if (type.IsSealed)
Console.WriteLine(" 特性: 密封");
if (type.IsStatic)
Console.WriteLine(" 特性: 静态");
}
}按类型种类过滤
csharp
/// <summary>
/// 按类型种类过滤命名空间中的类型
/// </summary>
public void FilterTypesByKind(INamespaceSymbol namespaceSymbol)
{
var allTypes = namespaceSymbol.GetTypeMembers();
// 获取所有类
var classes = allTypes.Where(t => t.TypeKind == TypeKind.Class).ToList();
Console.WriteLine($"类数量: {classes.Count}");
// 获取所有接口
var interfaces = allTypes.Where(t => t.TypeKind == TypeKind.Interface).ToList();
Console.WriteLine($"接口数量: {interfaces.Count}");
// 获取所有结构
var structs = allTypes.Where(t => t.TypeKind == TypeKind.Struct).ToList();
Console.WriteLine($"结构数量: {structs.Count}");
// 获取所有枚举
var enums = allTypes.Where(t => t.TypeKind == TypeKind.Enum).ToList();
Console.WriteLine($"枚举数量: {enums.Count}");
// 获取所有委托
var delegates = allTypes.Where(t => t.TypeKind == TypeKind.Delegate).ToList();
Console.WriteLine($"委托数量: {delegates.Count}");
}查找特定类型
csharp
/// <summary>
/// 在命名空间中查找特定类型
/// </summary>
public INamedTypeSymbol FindType(
INamespaceSymbol namespaceSymbol,
string typeName)
{
// 直接按名称查找
var types = namespaceSymbol.GetTypeMembers(typeName);
if (types.Length == 0)
{
return null;
}
// 如果有多个同名类型(泛型重载),返回第一个
return types[0];
}
/// <summary>
/// 递归查找类型(包括子命名空间)
/// </summary>
public INamedTypeSymbol FindTypeRecursive(
INamespaceSymbol namespaceSymbol,
string typeName)
{
// 在当前命名空间中查找
var type = FindType(namespaceSymbol, typeName);
if (type != null)
{
return type;
}
// 在子命名空间中递归查找
var childNamespaces = namespaceSymbol.GetNamespaceMembers();
foreach (var child in childNamespaces)
{
type = FindTypeRecursive(child, typeName);
if (type != null)
{
return type;
}
}
return null;
}获取命名空间中的所有成员
csharp
/// <summary>
/// 获取命名空间中的所有成员(包括类型和子命名空间)
/// </summary>
public void GetAllMembers(INamespaceSymbol namespaceSymbol)
{
var allMembers = namespaceSymbol.GetMembers();
Console.WriteLine($"命名空间 {namespaceSymbol.ToDisplayString()} 的所有成员:");
Console.WriteLine($"总数: {allMembers.Length}");
// 按成员种类分组
var membersByKind = allMembers.GroupBy(m => m.Kind);
foreach (var group in membersByKind)
{
Console.WriteLine($"\n{group.Key}:");
foreach (var member in group)
{
if (member is INamespaceSymbol ns)
{
Console.WriteLine($" 命名空间: {ns.Name}");
}
else if (member is INamedTypeSymbol type)
{
Console.WriteLine($" 类型: {type.Name} ({type.TypeKind})");
}
}
}
}🟢 全局命名空间处理
全局命名空间是命名空间树的根节点。
访问全局命名空间
csharp
/// <summary>
/// 访问全局命名空间
/// </summary>
public void AccessGlobalNamespace(Compilation compilation)
{
// 获取全局命名空间
var globalNamespace = compilation.GlobalNamespace;
Console.WriteLine($"是否是全局命名空间: {globalNamespace.IsGlobalNamespace}");
Console.WriteLine($"名称: {globalNamespace.Name}"); // 空字符串
Console.WriteLine($"显示名称: {globalNamespace.ToDisplayString()}"); // "<global namespace>"
// 全局命名空间没有父命名空间
Console.WriteLine($"父命名空间: {globalNamespace.ContainingNamespace}"); // null
}从全局命名空间开始遍历
csharp
/// <summary>
/// 从全局命名空间开始遍历所有命名空间
/// </summary>
public void TraverseFromGlobal(Compilation compilation)
{
var globalNamespace = compilation.GlobalNamespace;
Console.WriteLine("从全局命名空间开始遍历:");
TraverseNamespacesRecursive(globalNamespace, 0);
}
private void TraverseNamespacesRecursive(
INamespaceSymbol namespaceSymbol,
int level)
{
var indent = new string(' ', level * 2);
if (namespaceSymbol.IsGlobalNamespace)
{
Console.WriteLine($"{indent}[全局命名空间]");
}
else
{
Console.WriteLine($"{indent}{namespaceSymbol.Name}");
}
// 遍历子命名空间
foreach (var child in namespaceSymbol.GetNamespaceMembers())
{
TraverseNamespacesRecursive(child, level + 1);
}
}检查命名空间是否为空
csharp
/// <summary>
/// 检查命名空间是否为空(没有类型成员)
/// </summary>
public bool IsEmptyNamespace(INamespaceSymbol namespaceSymbol)
{
// 检查是否有类型成员
if (namespaceSymbol.GetTypeMembers().Length > 0)
{
return false;
}
// 递归检查子命名空间
foreach (var child in namespaceSymbol.GetNamespaceMembers())
{
if (!IsEmptyNamespace(child))
{
return false;
}
}
return true;
}注意
全局命名空间的 Name 属性返回空字符串,IsGlobalNamespace 属性返回 true。