Skip to content

符号系统高级主题

📚 文档导航

本文档介绍符号系统的高级主题,包括继承、接口、特性、显示格式和文档注释。

📖 文档系列

文档内容难度
符号系统基础基础概念、符号层次、快速入门🟢 入门
符号类型详解INamedTypeSymbol、IMethodSymbol、IPropertySymbol 等🟡 中级
符号操作获取、遍历、查询、比较符号🟡 中级
高级主题继承、接口、特性、显示格式、文档注释🔴 高级
最佳实践性能优化、实战场景、设计模式🟡 中级

继承和实现分析

深度继承分析

csharp
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

public class InheritanceAnalyzer
{
    public class InheritanceInfo
    {
        public List<INamedTypeSymbol> BaseTypes { get; set; } = new();
        public List<INamedTypeSymbol> Interfaces { get; set; } = new();
        public List<INamedTypeSymbol> DerivedTypes { get; set; } = new();
        public int InheritanceDepth { get; set; }
    }
    
    public InheritanceInfo AnalyzeInheritance(INamedTypeSymbol type, Compilation compilation)
    {
        var info = new InheritanceInfo();
        
        // 获取所有基类
        var current = type.BaseType;
        while (current != null && current.SpecialType != SpecialType.System_Object)
        {
            info.BaseTypes.Add(current);
            current = current.BaseType;
        }
        info.InheritanceDepth = info.BaseTypes.Count;
        
        // 获取所有接口(包括继承的)
        info.Interfaces.AddRange(type.AllInterfaces);
        
        // 查找派生类型(需要遍历整个编译单元)
        info.DerivedTypes.AddRange(FindDerivedTypes(type, compilation));
        
        return info;
    }
    
    private IEnumerable<INamedTypeSymbol> FindDerivedTypes(
        INamedTypeSymbol baseType, 
        Compilation compilation)
    {
        foreach (var tree in compilation.SyntaxTrees)
        {
            var model = compilation.GetSemanticModel(tree);
            var root = tree.GetRoot();
            
            var typeDeclarations = root.DescendantNodes()
                .OfType<TypeDeclarationSyntax>();
            
            foreach (var typeDecl in typeDeclarations)
            {
                var typeSymbol = model.GetDeclaredSymbol(typeDecl) as INamedTypeSymbol;
                if (typeSymbol != null && IsDerivedFrom(typeSymbol, baseType))
                {
                    yield return typeSymbol;
                }
            }
        }
    }
    
    private bool IsDerivedFrom(INamedTypeSymbol derived, INamedTypeSymbol baseType)
    {
        var current = derived.BaseType;
        while (current != null)
        {
            if (SymbolEqualityComparer.Default.Equals(current, baseType))
                return true;
            current = current.BaseType;
        }
        return false;
    }
    
    public void PrintInheritanceInfo(InheritanceInfo info, INamedTypeSymbol type)
    {
        Console.WriteLine($"类型: {type.ToDisplayString()}");
        Console.WriteLine($"继承深度: {info.InheritanceDepth}");
        
        if (info.BaseTypes.Any())
        {
            Console.WriteLine("\n基类:");
            foreach (var baseType in info.BaseTypes)
            {
                Console.WriteLine($"  - {baseType.ToDisplayString()}");
            }
        }
        
        if (info.Interfaces.Any())
        {
            Console.WriteLine("\n实现的接口:");
            foreach (var iface in info.Interfaces)
            {
                Console.WriteLine($"  - {iface.ToDisplayString()}");
            }
        }
        
        if (info.DerivedTypes.Any())
        {
            Console.WriteLine("\n派生类型:");
            foreach (var derived in info.DerivedTypes)
            {
                Console.WriteLine($"  - {derived.ToDisplayString()}");
            }
        }
    }
}

接口实现检查

csharp
public class InterfaceImplementationChecker
{
    public void CheckInterfaceImplementation(INamedTypeSymbol type)
    {
        Console.WriteLine($"检查类型: {type.ToDisplayString()}");
        
        foreach (var iface in type.Interfaces)
        {
            Console.WriteLine($"\n接口: {iface.ToDisplayString()}");
            
            foreach (var member in iface.GetMembers())
            {
                var implementation = type.FindImplementationForInterfaceMember(member);
                
                if (implementation != null)
                {
                    Console.WriteLine($"  {member.Name} -> {implementation.ToDisplayString()}");
                    
                    // 检查是否是显式实现
                    var isExplicit = implementation.ExplicitInterfaceImplementations.Any();
                    Console.WriteLine($"    显式实现: {isExplicit}");
                }
                else
                {
                    Console.WriteLine($"  {member.Name} -> 未实现!");
                }
            }
        }
    }
    
    public bool IsFullyImplemented(INamedTypeSymbol type)
    {
        if (type.IsAbstract)
            return true; // 抽象类可以不完全实现接口
        
        foreach (var iface in type.AllInterfaces)
        {
            foreach (var member in iface.GetMembers())
            {
                var implementation = type.FindImplementationForInterfaceMember(member);
                if (implementation == null)
                    return false;
            }
        }
        
        return true;
    }
}

特性(Attribute)处理

获取特性信息

csharp
public class AttributeHandling
{
    public void DemonstrateAttributes()
    {
        var code = @"
            using System;
            using System.ComponentModel;
            
            [Serializable]
            [Description(""This is a person class"")]
            public class Person
            {
                [Required]
                [MaxLength(100)]
                public string Name { get; set; }
                
                [Range(0, 150)]
                public int Age { get; set; }
                
                [Obsolete(""Use NewMethod instead"", false)]
                public void OldMethod() { }
                
                public void NewMethod() { }
            }
            
            // 自定义特性
            [AttributeUsage(AttributeTargets.Property)]
            public class RequiredAttribute : Attribute { }
            
            [AttributeUsage(AttributeTargets.Property)]
            public class MaxLengthAttribute : Attribute
            {
                public int Length { get; }
                public MaxLengthAttribute(int length) { Length = length; }
            }
            
            [AttributeUsage(AttributeTargets.Property)]
            public class RangeAttribute : Attribute
            {
                public int Min { get; }
                public int Max { get; }
                public RangeAttribute(int min, int max) 
                { 
                    Min = min; 
                    Max = max; 
                }
            }
        ";
        
        var tree = CSharpSyntaxTree.ParseText(code);
        var compilation = CreateCompilation(tree);
        var model = compilation.GetSemanticModel(tree);
        var root = tree.GetRoot();
        
        // 1. 获取类的特性
        var classDecl = root.DescendantNodes()
            .OfType<ClassDeclarationSyntax>()
            .First(c => c.Identifier.Text == "Person");
        
        var classSymbol = model.GetDeclaredSymbol(classDecl) as INamedTypeSymbol;
        
        Console.WriteLine($"类: {classSymbol.Name}");
        Console.WriteLine($"特性:");
        
        foreach (var attribute in classSymbol.GetAttributes())
        {
            Console.WriteLine($"  [{attribute.AttributeClass.Name}]");
            
            // 获取构造函数参数
            if (attribute.ConstructorArguments.Any())
            {
                Console.WriteLine($"    构造函数参数:");
                foreach (var arg in attribute.ConstructorArguments)
                {
                    Console.WriteLine($"      - {arg.Type.ToDisplayString()}: {arg.Value}");
                }
            }
            
            // 获取命名参数
            if (attribute.NamedArguments.Any())
            {
                Console.WriteLine($"    命名参数:");
                foreach (var arg in attribute.NamedArguments)
                {
                    Console.WriteLine($"      - {arg.Key} = {arg.Value.Value}");
                }
            }
        }
        Console.WriteLine();
        
        // 2. 获取属性的特性
        var properties = root.DescendantNodes()
            .OfType<PropertyDeclarationSyntax>();
        
        foreach (var property in properties)
        {
            var propertySymbol = model.GetDeclaredSymbol(property) as IPropertySymbol;
            
            if (propertySymbol.GetAttributes().Any())
            {
                Console.WriteLine($"属性: {propertySymbol.Name}");
                Console.WriteLine($"特性:");
                
                foreach (var attribute in propertySymbol.GetAttributes())
                {
                    Console.WriteLine($"  [{attribute.AttributeClass.Name}]");
                    
                    if (attribute.ConstructorArguments.Any())
                    {
                        Console.WriteLine($"    参数:");
                        foreach (var arg in attribute.ConstructorArguments)
                        {
                            Console.WriteLine($"      - {arg.Value}");
                        }
                    }
                }
                Console.WriteLine();
            }
        }
        
        // 3. 检查是否有特定特性
        var methods = root.DescendantNodes()
            .OfType<MethodDeclarationSyntax>();
        
        foreach (var method in methods)
        {
            var methodSymbol = model.GetDeclaredSymbol(method) as IMethodSymbol;
            
            var obsoleteAttr = methodSymbol.GetAttributes()
                .FirstOrDefault(a => a.AttributeClass.Name == "ObsoleteAttribute");
            
            if (obsoleteAttr != null)
            {
                Console.WriteLine($"方法: {methodSymbol.Name}");
                Console.WriteLine($"  已过时");
                
                if (obsoleteAttr.ConstructorArguments.Length > 0)
                {
                    var message = obsoleteAttr.ConstructorArguments[0].Value;
                    Console.WriteLine($"  消息: {message}");
                }
                
                if (obsoleteAttr.ConstructorArguments.Length > 1)
                {
                    var isError = obsoleteAttr.ConstructorArguments[1].Value;
                    Console.WriteLine($"  是错误: {isError}");
                }
                Console.WriteLine();
            }
        }
    }
    
    private Compilation CreateCompilation(SyntaxTree tree)
    {
        return CSharpCompilation.Create("temp")
            .AddReferences(
                MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
                MetadataReference.CreateFromFile(typeof(SerializableAttribute).Assembly.Location),
                MetadataReference.CreateFromFile(typeof(DescriptionAttribute).Assembly.Location),
                MetadataReference.CreateFromFile(typeof(ObsoleteAttribute).Assembly.Location)
            )
            .AddSyntaxTrees(tree);
    }
}

特性参数解析

csharp
public class AttributeArgumentParser
{
    public class AttributeInfo
    {
        public string AttributeName { get; set; }
        public Dictionary<string, object> ConstructorArguments { get; set; } = new();
        public Dictionary<string, object> NamedArguments { get; set; } = new();
    }
    
    public List<AttributeInfo> ParseAttributes(ISymbol symbol)
    {
        var result = new List<AttributeInfo>();
        
        foreach (var attr in symbol.GetAttributes())
        {
            var info = new AttributeInfo
            {
                AttributeName = attr.AttributeClass?.ToDisplayString()
            };
            
            // 解析构造函数参数
            for (int i = 0; i < attr.ConstructorArguments.Length; i++)
            {
                var arg = attr.ConstructorArguments[i];
                var paramName = attr.AttributeConstructor?.Parameters[i].Name ?? $"arg{i}";
                info.ConstructorArguments[paramName] = GetArgumentValue(arg);
            }
            
            // 解析命名参数
            foreach (var namedArg in attr.NamedArguments)
            {
                info.NamedArguments[namedArg.Key] = GetArgumentValue(namedArg.Value);
            }
            
            result.Add(info);
        }
        
        return result;
    }
    
    private object GetArgumentValue(TypedConstant constant)
    {
        if (constant.IsNull)
            return null;
        
        if (constant.Kind == TypedConstantKind.Array)
        {
            return constant.Values.Select(GetArgumentValue).ToArray();
        }
        
        if (constant.Kind == TypedConstantKind.Type)
        {
            return (constant.Value as ITypeSymbol)?.ToDisplayString();
        }
        
        return constant.Value;
    }
    
    public void PrintAttributeInfo(List<AttributeInfo> attributes)
    {
        foreach (var attr in attributes)
        {
            Console.WriteLine($"特性: {attr.AttributeName}");
            
            if (attr.ConstructorArguments.Any())
            {
                Console.WriteLine("  构造函数参数:");
                foreach (var arg in attr.ConstructorArguments)
                {
                    Console.WriteLine($"    {arg.Key} = {arg.Value}");
                }
            }
            
            if (attr.NamedArguments.Any())
            {
                Console.WriteLine("  命名参数:");
                foreach (var arg in attr.NamedArguments)
                {
                    Console.WriteLine($"    {arg.Key} = {arg.Value}");
                }
            }
        }
    }
}

特性处理工具

csharp
public static class AttributeHelpers
{
    // 检查符号是否有特定特性
    public static bool HasAttribute(ISymbol symbol, string attributeName)
    {
        return symbol.GetAttributes()
            .Any(a => a.AttributeClass?.Name == attributeName ||
                     a.AttributeClass?.ToDisplayString() == attributeName);
    }
    
    // 获取特定特性
    public static AttributeData GetAttribute(ISymbol symbol, string attributeName)
    {
        return symbol.GetAttributes()
            .FirstOrDefault(a => a.AttributeClass?.Name == attributeName ||
                                a.AttributeClass?.ToDisplayString() == attributeName);
    }
    
    // 获取特性的构造函数参数值
    public static T GetAttributeArgument<T>(AttributeData attribute, int index, T defaultValue = default)
    {
        if (attribute.ConstructorArguments.Length > index)
        {
            var arg = attribute.ConstructorArguments[index];
            if (arg.Value is T value)
            {
                return value;
            }
        }
        return defaultValue;
    }
    
    // 获取特性的命名参数值
    public static T GetAttributeNamedArgument<T>(AttributeData attribute, string name, T defaultValue = default)
    {
        var namedArg = attribute.NamedArguments
            .FirstOrDefault(a => a.Key == name);
        
        if (namedArg.Value.Value is T value)
        {
            return value;
        }
        
        return defaultValue;
    }
    
    // 检查是否有 Obsolete 特性
    public static bool IsObsolete(ISymbol symbol)
    {
        return HasAttribute(symbol, "ObsoleteAttribute");
    }
    
    // 获取 Obsolete 消息
    public static string GetObsoleteMessage(ISymbol symbol)
    {
        var attr = GetAttribute(symbol, "ObsoleteAttribute");
        return attr != null ? GetAttributeArgument<string>(attr, 0, "") : null;
    }
}

符号的显示格式

SymbolDisplayFormat 详解

Roslyn 提供了灵活的符号显示格式化选项:

csharp
public class SymbolDisplayExamples
{
    public void DemonstrateDisplayFormats(INamedTypeSymbol typeSymbol)
    {
        // 1. 默认格式
        var defaultFormat = typeSymbol.ToDisplayString();
        Console.WriteLine($"默认: {defaultFormat}");
        // 输出: MyNamespace.MyClass<T>
        
        // 2. 仅类型名称
        var nameOnly = typeSymbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat);
        Console.WriteLine($"最小化: {nameOnly}");
        // 输出: MyClass<T>
        
        // 3. 完全限定名称
        var fullyQualified = typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
        Console.WriteLine($"完全限定: {fullyQualified}");
        // 输出: global::MyNamespace.MyClass<T>
        
        // 4. 自定义格式
        var customFormat = new SymbolDisplayFormat(
            typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
            genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters,
            memberOptions: SymbolDisplayMemberOptions.IncludeParameters |
                          SymbolDisplayMemberOptions.IncludeType,
            parameterOptions: SymbolDisplayParameterOptions.IncludeType |
                            SymbolDisplayParameterOptions.IncludeName,
            miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes
        );
        
        var custom = typeSymbol.ToDisplayString(customFormat);
        Console.WriteLine($"自定义: {custom}");
    }
    
    public void DemonstrateMethodDisplayFormats(IMethodSymbol methodSymbol)
    {
        // 方法的不同显示格式
        var formats = new[]
        {
            SymbolDisplayFormat.MinimallyQualifiedFormat,
            SymbolDisplayFormat.FullyQualifiedFormat,
            new SymbolDisplayFormat(
                memberOptions: SymbolDisplayMemberOptions.IncludeParameters |
                              SymbolDisplayMemberOptions.IncludeType |
                              SymbolDisplayMemberOptions.IncludeAccessibility,
                parameterOptions: SymbolDisplayParameterOptions.IncludeType |
                                SymbolDisplayParameterOptions.IncludeName |
                                SymbolDisplayParameterOptions.IncludeDefaultValue,
                miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes
            )
        };
        
        Console.WriteLine($"方法: {methodSymbol.Name}");
        foreach (var format in formats)
        {
            Console.WriteLine($"  {methodSymbol.ToDisplayString(format)}");
        }
    }
}

符号的元数据名称

csharp
public class MetadataNameExamples
{
    public void GetMetadataNames(INamedTypeSymbol typeSymbol)
    {
        // 获取元数据名称(用于反射)
        var metadataName = typeSymbol.MetadataName;
        Console.WriteLine($"元数据名称: {metadataName}");
        // 对于泛型类型,输出: MyClass`1
        
        // 获取完整的元数据名称
        var fullMetadataName = GetFullMetadataName(typeSymbol);
        Console.WriteLine($"完整元数据名称: {fullMetadataName}");
        // 输出: MyNamespace.MyClass`1
    }
    
    private string GetFullMetadataName(ISymbol symbol)
    {
        if (symbol.ContainingSymbol is INamespaceSymbol ns && !ns.IsGlobalNamespace)
        {
            return $"{GetFullMetadataName(ns)}.{symbol.MetadataName}";
        }
        return symbol.MetadataName;
    }
}

符号的文档注释

获取 XML 文档注释

csharp
public class DocumentationCommentExamples
{
    public void GetDocumentation(ISymbol symbol)
    {
        // 获取 XML 文档注释
        var xml = symbol.GetDocumentationCommentXml();
        Console.WriteLine($"XML 文档:\n{xml}");
        
        // 获取摘要
        var summary = GetSummary(xml);
        Console.WriteLine($"摘要: {summary}");
        
        // 获取参数说明(对于方法)
        if (symbol is IMethodSymbol method)
        {
            foreach (var param in method.Parameters)
            {
                var paramDoc = GetParameterDocumentation(xml, param.Name);
                Console.WriteLine($"参数 {param.Name}: {paramDoc}");
            }
            
            // 获取返回值说明
            var returns = GetReturns(xml);
            if (!string.IsNullOrEmpty(returns))
            {
                Console.WriteLine($"返回值: {returns}");
            }
        }
        
        // 获取示例
        var example = GetExample(xml);
        if (!string.IsNullOrEmpty(example))
        {
            Console.WriteLine($"示例:\n{example}");
        }
        
        // 获取备注
        var remarks = GetRemarks(xml);
        if (!string.IsNullOrEmpty(remarks))
        {
            Console.WriteLine($"备注: {remarks}");
        }
    }
    
    private string GetSummary(string xml)
    {
        if (string.IsNullOrEmpty(xml)) return string.Empty;
        
        try
        {
            var doc = XDocument.Parse(xml);
            var summary = doc.Descendants("summary").FirstOrDefault();
            return summary?.Value.Trim() ?? string.Empty;
        }
        catch
        {
            return string.Empty;
        }
    }
    
    private string GetParameterDocumentation(string xml, string paramName)
    {
        if (string.IsNullOrEmpty(xml)) return string.Empty;
        
        try
        {
            var doc = XDocument.Parse(xml);
            var param = doc.Descendants("param")
                .FirstOrDefault(p => p.Attribute("name")?.Value == paramName);
            return param?.Value.Trim() ?? string.Empty;
        }
        catch
        {
            return string.Empty;
        }
    }
    
    private string GetReturns(string xml)
    {
        if (string.IsNullOrEmpty(xml)) return string.Empty;
        
        try
        {
            var doc = XDocument.Parse(xml);
            var returns = doc.Descendants("returns").FirstOrDefault();
            return returns?.Value.Trim() ?? string.Empty;
        }
        catch
        {
            return string.Empty;
        }
    }
    
    private string GetExample(string xml)
    {
        if (string.IsNullOrEmpty(xml)) return string.Empty;
        
        try
        {
            var doc = XDocument.Parse(xml);
            var example = doc.Descendants("example").FirstOrDefault();
            return example?.Value.Trim() ?? string.Empty;
        }
        catch
        {
            return string.Empty;
        }
    }
    
    private string GetRemarks(string xml)
    {
        if (string.IsNullOrEmpty(xml)) return string.Empty;
        
        try
        {
            var doc = XDocument.Parse(xml);
            var remarks = doc.Descendants("remarks").FirstOrDefault();
            return remarks?.Value.Trim() ?? string.Empty;
        }
        catch
        {
            return string.Empty;
        }
    }
}

符号的可访问性分析

访问修饰符详解

csharp
public class AccessibilityAnalysis
{
    public void AnalyzeAccessibility(ISymbol symbol)
    {
        var accessibility = symbol.DeclaredAccessibility;
        
        Console.WriteLine($"符号: {symbol.Name}");
        Console.WriteLine($"访问修饰符: {accessibility}");
        
        // 检查各种访问级别
        Console.WriteLine($"是公共的: {accessibility == Accessibility.Public}");
        Console.WriteLine($"是私有的: {accessibility == Accessibility.Private}");
        Console.WriteLine($"是受保护的: {accessibility == Accessibility.Protected}");
        Console.WriteLine($"是内部的: {accessibility == Accessibility.Internal}");
        Console.WriteLine($"是受保护的内部: {accessibility == Accessibility.ProtectedOrInternal}");
        Console.WriteLine($"是私有受保护的: {accessibility == Accessibility.ProtectedAndInternal}");
        
        // 检查是否可以从外部访问
        bool isPubliclyAccessible = accessibility == Accessibility.Public;
        Console.WriteLine($"可公开访问: {isPubliclyAccessible}");
    }
    
    public bool IsAccessibleFrom(ISymbol symbol, INamedTypeSymbol fromType)
    {
        var accessibility = symbol.DeclaredAccessibility;
        
        switch (accessibility)
        {
            case Accessibility.Public:
                return true;
                
            case Accessibility.Private:
                return SymbolEqualityComparer.Default.Equals(
                    symbol.ContainingType, fromType);
                
            case Accessibility.Protected:
                return IsInheritanceRelated(fromType, symbol.ContainingType);
                
            case Accessibility.Internal:
                return SymbolEqualityComparer.Default.Equals(
                    symbol.ContainingAssembly, fromType.ContainingAssembly);
                
            case Accessibility.ProtectedOrInternal:
                return IsInheritanceRelated(fromType, symbol.ContainingType) ||
                       SymbolEqualityComparer.Default.Equals(
                           symbol.ContainingAssembly, fromType.ContainingAssembly);
                
            default:
                return false;
        }
    }
    
    private bool IsInheritanceRelated(INamedTypeSymbol derived, INamedTypeSymbol baseType)
    {
        var current = derived;
        while (current != null)
        {
            if (SymbolEqualityComparer.Default.Equals(current, baseType))
                return true;
            current = current.BaseType;
        }
        return false;
    }
}

下一步


🔗 相关资源


最后更新: 2025-01-21

基于 MIT 许可发布