语义模型高级主题
📚 文档导航
本文档介绍语义模型的高级主题,包括泛型、继承、特性和类型转换。
📖 文档系列
| 文档 | 内容 | 难度 |
|---|---|---|
| 语义模型基础 | 基础概念、快速入门、核心功能 | 🟢 入门 |
| 类型信息获取 | GetTypeInfo、常量值、TypeInfo 详解 | 🟡 中级 |
| 符号信息获取 | GetDeclaredSymbol、GetSymbolInfo、符号遍历 | 🟡 中级 |
| 高级主题 ⭐ | 泛型、继承、特性、类型转换 | 🔴 高级 |
| 最佳实践 | 性能优化、常见问题、实战场景 | 🟡 中级 |
泛型类型处理
泛型类和方法
csharp
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
public class GenericTypeHandling
{
public void DemonstrateGenerics()
{
var code = @"
using System.Collections.Generic;
public class Container<T>
{
public T Value { get; set; }
public void SetValue(T value)
{
Value = value;
}
public T GetValue()
{
return Value;
}
}
public class MultiGeneric<T, U> where T : class where U : struct
{
public T First { get; set; }
public U Second { get; set; }
}
public class Usage
{
public void Test()
{
var intContainer = new Container<int>();
var stringContainer = new Container<string>();
var list = new List<int>();
var dict = new Dictionary<string, int>();
}
}
";
var tree = CSharpSyntaxTree.ParseText(code);
var compilation = CreateCompilation(tree);
var model = compilation.GetSemanticModel(tree);
var root = tree.GetRoot();
// 1. 分析泛型类定义
var genericClasses = root.DescendantNodes()
.OfType<ClassDeclarationSyntax>()
.Where(c => c.TypeParameterList != null);
foreach (var classDecl in genericClasses)
{
var classSymbol = model.GetDeclaredSymbol(classDecl) as INamedTypeSymbol;
Console.WriteLine($"泛型类: {classSymbol.Name}");
Console.WriteLine($" 是泛型: {classSymbol.IsGenericType}");
Console.WriteLine($" 类型参数数量: {classSymbol.TypeParameters.Length}");
Console.WriteLine($" 类型参数:");
foreach (var typeParam in classSymbol.TypeParameters)
{
Console.WriteLine($" - {typeParam.Name}");
Console.WriteLine($" 有引用类型约束: {typeParam.HasReferenceTypeConstraint}");
Console.WriteLine($" 有值类型约束: {typeParam.HasValueTypeConstraint}");
Console.WriteLine($" 有构造函数约束: {typeParam.HasConstructorConstraint}");
if (typeParam.ConstraintTypes.Any())
{
Console.WriteLine($" 类型约束:");
foreach (var constraint in typeParam.ConstraintTypes)
{
Console.WriteLine($" - {constraint.ToDisplayString()}");
}
}
}
Console.WriteLine();
}
// 2. 分析泛型类型的使用
var objectCreations = root.DescendantNodes()
.OfType<ObjectCreationExpressionSyntax>();
foreach (var creation in objectCreations)
{
var typeInfo = model.GetTypeInfo(creation);
var type = typeInfo.Type as INamedTypeSymbol;
if (type != null && type.IsGenericType)
{
Console.WriteLine($"泛型类型实例: {creation.Type}");
Console.WriteLine($" 完整类型: {type.ToDisplayString()}");
Console.WriteLine($" 原始定义: {type.OriginalDefinition.ToDisplayString()}");
Console.WriteLine($" 是构造的泛型类型: {type.IsGenericType && !type.IsUnboundGenericType}");
Console.WriteLine($" 类型参数:");
foreach (var typeArg in type.TypeArguments)
{
Console.WriteLine($" - {typeArg.ToDisplayString()}");
Console.WriteLine($" 种类: {typeArg.TypeKind}");
Console.WriteLine($" 是值类型: {typeArg.IsValueType}");
Console.WriteLine($" 是引用类型: {typeArg.IsReferenceType}");
}
Console.WriteLine();
}
}
}
private Compilation CreateCompilation(SyntaxTree tree)
{
return CSharpCompilation.Create("temp")
.AddReferences(
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(typeof(List<>).Assembly.Location)
)
.AddSyntaxTrees(tree);
}
}💡 泛型类型关键概念
- IsGenericType: 是否是泛型类型
- TypeParameters: 类型参数(定义时)
- TypeArguments: 类型参数(使用时)
- OriginalDefinition: 原始泛型定义
泛型类型实用工具
csharp
public static class GenericTypeHelpers
{
// 检查类型是否是特定泛型类型的实例
public static bool IsGenericTypeOf(ITypeSymbol type, string genericTypeName)
{
if (type is INamedTypeSymbol namedType && namedType.IsGenericType)
{
var originalDefinition = namedType.OriginalDefinition.ToDisplayString();
return originalDefinition.StartsWith(genericTypeName + "<");
}
return false;
}
// 获取泛型类型参数
public static ITypeSymbol[] GetGenericArguments(ITypeSymbol type)
{
if (type is INamedTypeSymbol namedType && namedType.IsGenericType)
{
return namedType.TypeArguments.ToArray();
}
return Array.Empty<ITypeSymbol>();
}
// 检查是否是 List<T>
public static bool IsList(ITypeSymbol type)
{
return IsGenericTypeOf(type, "System.Collections.Generic.List");
}
// 检查是否是 Dictionary<TKey, TValue>
public static bool IsDictionary(ITypeSymbol type)
{
return IsGenericTypeOf(type, "System.Collections.Generic.Dictionary");
}
// 获取 List<T> 的元素类型
public static ITypeSymbol GetListElementType(ITypeSymbol type)
{
if (IsList(type))
{
var args = GetGenericArguments(type);
return args.Length > 0 ? args[0] : null;
}
return null;
}
}继承和接口分析
分析类型层次结构
csharp
public class InheritanceAnalysis
{
public void AnalyzeHierarchy()
{
var code = @"
interface IAnimal { void MakeSound(); }
interface IMammal : IAnimal { void Feed(); }
abstract class Animal : IAnimal
{
public abstract void MakeSound();
}
class Dog : Animal, IMammal
{
public override void MakeSound() { }
public void Feed() { }
}
class GermanShepherd : Dog { }
";
var tree = CSharpSyntaxTree.ParseText(code);
var compilation = CreateCompilation(tree);
var model = compilation.GetSemanticModel(tree);
var root = tree.GetRoot();
var germanShepherd = root.DescendantNodes()
.OfType<ClassDeclarationSyntax>()
.First(c => c.Identifier.Text == "GermanShepherd");
var symbol = model.GetDeclaredSymbol(germanShepherd) as INamedTypeSymbol;
Console.WriteLine($"类: {symbol.Name}");
Console.WriteLine($"\n继承链:");
var current = symbol;
while (current != null)
{
Console.WriteLine($" - {current.ToDisplayString()}");
current = current.BaseType;
}
Console.WriteLine($"\n实现的接口:");
foreach (var iface in symbol.AllInterfaces)
{
Console.WriteLine($" - {iface.ToDisplayString()}");
}
Console.WriteLine($"\n所有成员:");
foreach (var member in symbol.GetMembers())
{
Console.WriteLine($" - {member.ToDisplayString()}");
}
}
private Compilation CreateCompilation(SyntaxTree tree)
{
return CSharpCompilation.Create("temp")
.AddReferences(MetadataReference.CreateFromFile(typeof(object).Assembly.Location))
.AddSyntaxTrees(tree);
}
}继承关系检查工具
csharp
public static class InheritanceHelpers
{
// 检查是否继承自特定类
public static bool InheritsFrom(ITypeSymbol derived, ITypeSymbol baseType)
{
var current = derived.BaseType;
while (current != null)
{
if (SymbolEqualityComparer.Default.Equals(current, baseType))
{
return true;
}
current = current.BaseType;
}
return false;
}
// 检查是否实现特定接口
public static bool ImplementsInterface(ITypeSymbol type, ITypeSymbol interfaceType)
{
return type.AllInterfaces.Any(i =>
SymbolEqualityComparer.Default.Equals(i, interfaceType));
}
// 检查是否实现特定接口(按名称)
public static bool ImplementsInterface(ITypeSymbol type, string interfaceName)
{
return type.AllInterfaces.Any(i =>
i.ToDisplayString() == interfaceName);
}
// 获取所有基类
public static IEnumerable<INamedTypeSymbol> GetBaseTypes(ITypeSymbol type)
{
var current = type.BaseType;
while (current != null)
{
yield return current;
current = current.BaseType;
}
}
// 获取类型层次深度
public static int GetInheritanceDepth(ITypeSymbol type)
{
int depth = 0;
var current = type.BaseType;
while (current != null)
{
depth++;
current = current.BaseType;
}
return depth;
}
}特性(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();
}
}
}
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 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;
}
}类型转换和兼容性
ClassifyConversion 方法
csharp
public class ConversionExamples
{
public void DemonstrateConversions()
{
var code = @"
class Base { }
class Derived : Base { }
interface IExample { }
class Implementation : IExample { }
class ConversionTests
{
public void Test()
{
// 值类型转换
int i = 5;
long l = i; // 隐式转换
// 引用类型转换
Derived d = new Derived();
Base b = d; // 隐式向上转换
// 接口转换
Implementation impl = new Implementation();
IExample iface = impl; // 隐式转换
// 显式转换
object obj = ""hello"";
string str = (string)obj;
}
}
";
var tree = CSharpSyntaxTree.ParseText(code);
var compilation = CreateCompilation(tree);
var model = compilation.GetSemanticModel(tree);
var root = tree.GetRoot();
// 分析所有赋值语句的转换
var assignments = root.DescendantNodes()
.OfType<AssignmentExpressionSyntax>()
.Where(a => a.IsKind(SyntaxKind.SimpleAssignmentExpression));
foreach (var assignment in assignments)
{
var leftType = model.GetTypeInfo(assignment.Left).Type;
var rightType = model.GetTypeInfo(assignment.Right).Type;
if (leftType != null && rightType != null)
{
var conversion = model.ClassifyConversion(assignment.Right, leftType);
Console.WriteLine($"赋值: {assignment}");
Console.WriteLine($" 源类型: {rightType.ToDisplayString()}");
Console.WriteLine($" 目标类型: {leftType.ToDisplayString()}");
Console.WriteLine($" 转换存在: {conversion.Exists}");
Console.WriteLine($" 是恒等转换: {conversion.IsIdentity}");
Console.WriteLine($" 是隐式转换: {conversion.IsImplicit}");
Console.WriteLine($" 是显式转换: {conversion.IsExplicit}");
Console.WriteLine($" 是引用转换: {conversion.IsReference}");
Console.WriteLine($" 是数值转换: {conversion.IsNumeric}");
Console.WriteLine($" 是装箱转换: {conversion.IsBoxing}");
Console.WriteLine($" 是拆箱转换: {conversion.IsUnboxing}");
Console.WriteLine();
}
}
}
private Compilation CreateCompilation(SyntaxTree tree)
{
return CSharpCompilation.Create("temp")
.AddReferences(MetadataReference.CreateFromFile(typeof(object).Assembly.Location))
.AddSyntaxTrees(tree);
}
}转换检查工具
csharp
public static class ConversionHelpers
{
// 检查类型兼容性
public static bool CanConvert(
SemanticModel model,
ExpressionSyntax expression,
ITypeSymbol targetType)
{
var conversion = model.ClassifyConversion(expression, targetType);
return conversion.Exists;
}
// 检查是否可以隐式转换
public static bool CanImplicitlyConvert(
SemanticModel model,
ExpressionSyntax expression,
ITypeSymbol targetType)
{
var conversion = model.ClassifyConversion(expression, targetType);
return conversion.IsImplicit;
}
// 检查是否需要显式转换
public static bool RequiresExplicitConversion(
SemanticModel model,
ExpressionSyntax expression,
ITypeSymbol targetType)
{
var conversion = model.ClassifyConversion(expression, targetType);
return conversion.Exists && conversion.IsExplicit && !conversion.IsImplicit;
}
// 检查是否是装箱转换
public static bool IsBoxingConversion(
SemanticModel model,
ExpressionSyntax expression,
ITypeSymbol targetType)
{
var conversion = model.ClassifyConversion(expression, targetType);
return conversion.IsBoxing;
}
// 检查是否是拆箱转换
public static bool IsUnboxingConversion(
SemanticModel model,
ExpressionSyntax expression,
ITypeSymbol targetType)
{
var conversion = model.ClassifyConversion(expression, targetType);
return conversion.IsUnboxing;
}
}💡 转换类型
- IsIdentity: 恒等转换(相同类型)
- IsImplicit: 隐式转换(自动)
- IsExplicit: 显式转换(需要强制转换)
- IsReference: 引用转换
- IsNumeric: 数值转换
- IsBoxing: 装箱转换
- IsUnboxing: 拆箱转换
下一步
🔗 相关资源
最后更新: 2025-01-21