using System.Globalization;
using Microsoft.CodeAnalysis;

namespace Dpz.Core.SourceGenerator;

/// <summary>
/// 源生成器内部统一的 Roslyn 符号显示工具。
/// </summary>
internal static class SymbolDisplay
{
    private static readonly SymbolDisplayFormat TypeNameFormat =
        SymbolDisplayFormat.FullyQualifiedFormat.WithMiscellaneousOptions(
            SymbolDisplayFormat.FullyQualifiedFormat.MiscellaneousOptions
                | SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier
        );

    /// <summary>
    /// 输出可直接写入生成源码的完整类型名称,并保留 nullable 标记。
    /// </summary>
    internal static string ToFullyQualifiedTypeName(ITypeSymbol type) =>
        type.ToDisplayString(TypeNameFormat);

    /// <summary>
    /// 将接口参数默认值转换为方法签名中的 C# 字面量。
    /// </summary>
    internal static string ToDefaultValueLiteral(IParameterSymbol parameter)
    {
        if (!parameter.HasExplicitDefaultValue)
        {
            return string.Empty;
        }

        if (parameter.ExplicitDefaultValue is null)
        {
            return " = default";
        }

        if (parameter.Type.SpecialType == SpecialType.System_String)
        {
            return " = " + ToCSharpStringLiteral((string)parameter.ExplicitDefaultValue);
        }

        if (parameter.Type.SpecialType == SpecialType.System_Boolean)
        {
            return (bool)parameter.ExplicitDefaultValue ? " = true" : " = false";
        }

        if (parameter.Type.TypeKind == TypeKind.Enum)
        {
            return " = "
                + ToFullyQualifiedTypeName(parameter.Type)
                + "."
                + parameter.ExplicitDefaultValue;
        }

        return " = "
            + Convert.ToString(parameter.ExplicitDefaultValue, CultureInfo.InvariantCulture);
    }

    internal static string ToCSharpStringLiteral(string value)
    {
        return "\"" + value.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\"";
    }
}
⚠⚠    以下内容为AI分析的结果,请根据实际情况进行判断。

代码解释

这是一个用于 Roslyn 源代码生成器的辅助工具类,主要用于将编译时的符号(Symbol)信息转换为可以直接写入生成代码的字符串格式。

主要功能

1. 类型名称格式化 (TypeNameFormat)

private static readonly SymbolDisplayFormat TypeNameFormat = ...
  • 定义了一个静态的显示格式配置
  • 基于 FullyQualifiedFormat(完全限定名格式,如 global::System.String
  • 额外添加了 IncludeNullableReferenceTypeModifier 选项,使得可空引用类型标记(?)会被保留

2. 完全限定类型名转换 (ToFullyQualifiedTypeName)

internal static string ToFullyQualifiedTypeName(ITypeSymbol type)
  • 将 Roslyn 的 ITypeSymbol 转换为完整的类型名称字符串
  • 例如:System.String?global::System.String?
  • 这样生成的代码不会有命名空间冲突问题

3. 参数默认值转换 (ToDefaultValueLiteral)

internal static string ToDefaultValueLiteral(IParameterSymbol parameter)

这是核心方法,将接口或方法参数的默认值转换为 C# 代码字符串:

情况返回值示例
无默认值"" (空字符串)
null" = default"
字符串类型" = \"hello\""
布尔类型" = true"" = false"
枚举类型" = global::MyNamespace.MyEnum.Value"
数值类型" = 42"

4. 字符串字面量转义 (ToCSharpStringLiteral)

internal static string ToCSharpStringLiteral(string value)
  • 将普通字符串转换为 C# 代码中的字符串字面量
  • 处理反斜杠和双引号的转义
  • 例如:hello"world"hello\"world"

应用场景

这个工具类典型用于 Source Generator 中,当需要生成实现接口的代理类时:

// 源接口
interface IService 
{
    void Method(string? name = "default", int count = 5);
}

// 源生成器会使用此工具类生成:
class ServiceProxy : IService 
{
    public void Method(string? name = "default", int count = 5) { ... }
}

技术亮点

  • ✅ 使用 InvariantCulture 确保跨文化数值格式一致性
  • ✅ 完整处理可空引用类型(C# 8.0+)
  • ✅ 避免生成代码的命名空间污染(使用 global::
  • ✅ 正确处理各种特殊类型(枚举、布尔、字符串等)
评论加载中...