符号系统高级主题
📚 文档导航
本文档介绍符号系统的高级主题,包括继承、接口、特性、显示格式和文档注释。
📖 文档系列
| 文档 | 内容 | 难度 |
|---|---|---|
| 符号系统基础 | 基础概念、符号层次、快速入门 | 🟢 入门 |
| 符号类型详解 | 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