using System.Collections.Immutable;
using Dpz.Core.SourceGenerator.Models;
using Microsoft.CodeAnalysis;
namespace Dpz.Core.SourceGenerator;
/// <summary>
/// 从服务接口读取生成装饰器所需的完整契约。
/// </summary>
internal static class InterfaceContractInspector
{
internal static ImmutableArray<InterfaceMethod> GetMethods(INamedTypeSymbol interfaceType)
{
return
[
.. GetMembers(interfaceType)
.OfType<IMethodSymbol>()
.Where(method => method.MethodKind == MethodKind.Ordinary)
.Select(method => new InterfaceMethod(
method.Name,
SymbolDisplay.ToFullyQualifiedTypeName(method.ReturnType),
GetTypeParameterList(method),
GetConstraintClauses(method),
[
.. method.Parameters.Select(parameter => new CachedParameter(
parameter.Name,
SymbolDisplay.ToFullyQualifiedTypeName(parameter.Type),
parameter.RefKind,
parameter.HasExplicitDefaultValue,
SymbolDisplay.ToDefaultValueLiteral(parameter),
parameter.IsParams
)),
]
)),
];
}
internal static ImmutableArray<InterfaceProperty> GetProperties(INamedTypeSymbol interfaceType)
{
return
[
.. GetMembers(interfaceType)
.OfType<IPropertySymbol>()
.Where(property => !property.IsStatic)
.Select(property => new InterfaceProperty(
property.Name,
SymbolDisplay.ToFullyQualifiedTypeName(property.Type),
property.GetMethod is not null,
property.SetMethod is not null
)),
];
}
internal static ImmutableArray<InterfaceEvent> GetEvents(INamedTypeSymbol interfaceType)
{
return
[
.. GetMembers(interfaceType)
.OfType<IEventSymbol>()
.Where(@event => !@event.IsStatic)
.Select(@event => new InterfaceEvent(
@event.Name,
SymbolDisplay.ToFullyQualifiedTypeName(@event.Type)
)),
];
}
private static IEnumerable<ISymbol> GetMembers(INamedTypeSymbol interfaceType)
{
foreach (
var inheritedInterface in interfaceType.AllInterfaces.OrderBy(
type => type.ToDisplayString(),
StringComparer.Ordinal
)
)
{
foreach (var member in inheritedInterface.GetMembers())
{
yield return member;
}
}
foreach (var member in interfaceType.GetMembers())
{
yield return member;
}
}
private static string GetTypeParameterList(IMethodSymbol method)
{
if (method.TypeParameters.Length == 0)
{
return string.Empty;
}
return "<"
+ string.Join(", ", method.TypeParameters.Select(parameter => parameter.Name))
+ ">";
}
private static string GetConstraintClauses(IMethodSymbol method)
{
if (method.TypeParameters.Length == 0)
{
return string.Empty;
}
return string.Join(
string.Empty,
method.TypeParameters.Select(GetConstraintClause).Where(clause => clause.Length > 0)
);
}
private static string GetConstraintClause(ITypeParameterSymbol typeParameter)
{
var constraints = new List<string>();
if (typeParameter.HasUnmanagedTypeConstraint)
{
constraints.Add("unmanaged");
}
else if (typeParameter.HasValueTypeConstraint)
{
constraints.Add("struct");
}
else if (typeParameter.HasReferenceTypeConstraint)
{
constraints.Add("class");
}
else if (typeParameter.HasNotNullConstraint)
{
constraints.Add("notnull");
}
constraints.AddRange(
typeParameter.ConstraintTypes.Select(SymbolDisplay.ToFullyQualifiedTypeName)
);
if (typeParameter.HasConstructorConstraint)
{
constraints.Add("new()");
}
if (constraints.Count == 0)
{
return string.Empty;
}
return " where " + typeParameter.Name + " : " + string.Join(", ", constraints);
}
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
代码解释
这是一个用于 C# 源代码生成器的实用工具类,专门用于检查和提取接口的契约信息。它使用 Roslyn API 来分析接口类型并提取其成员信息。
主要功能
1. GetMethods - 提取接口方法
internal static ImmutableArray<InterfaceMethod> GetMethods(INamedTypeSymbol interfaceType)
- 获取接口中所有普通方法(排除构造函数、操作符重载等特殊方法)
- 提取每个方法的:
- 方法名
- 完全限定的返回类型
- 泛型类型参数列表
- 泛型约束子句
- 参数列表(包括参数名、类型、ref/out/in修饰符、默认值、params修饰符)
2. GetProperties - 提取接口属性
internal static ImmutableArray<InterfaceProperty> GetProperties(INamedTypeSymbol interfaceType)
- 获取所有非静态属性
- 提取每个属性的:
- 属性名
- 完全限定类型
- 是否有getter
- 是否有setter
3. GetEvents - 提取接口事件
internal static ImmutableArray<InterfaceEvent> GetEvents(INamedTypeSymbol interfaceType)
- 获取所有非静态事件
- 提取事件名和完全限定的事件处理器类型
辅助方法
GetMembers - 递归获取所有成员
- 先遍历所有继承的接口(按字符串顺序排序)
- 再遍历当前接口的直接成员
- 这样可以收集接口及其所有基接口的成员
GetTypeParameterList - 生成泛型参数列表
- 例如:
<T, U>或空字符串
GetConstraintClauses - 生成泛型约束
- 例如:
where T : class, IDisposable where U : struct
GetConstraintClause - 生成单个类型参数的约束
按优先级处理约束:
unmanaged(非托管类型)struct(值类型)class(引用类型)notnull(不可为空)- 类型约束(接口或基类)
new()(构造函数约束)
使用场景
这个类通常用于生成装饰器模式代码,例如:
- 自动生成代理类
- 创建拦截器
- 实现 AOP(面向切面编程)
通过完整提取接口契约,可以自动生成实现相同接口的包装类,保持完整的类型信息和约束。
评论加载中...