Skip to content

命名空间详解

简介

本文档详细介绍 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


🔗 相关 API


📚 下一步

基于 MIT 许可发布