You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在调用model.GetDeclaredSymbol时获取SynthesizedIntrinsicOperatorSymbol而非SourceUserDefinedOperatorSymbol

如何将自定义运算符的SourceUserDefinedOperatorSymbol转换为SynthesizedIntrinsicOperatorSymbol?

我在处理Roslyn运算符解析时遇到了一个棘手的问题:当我在自定义的System.Int32结构体中声明>运算符,并用GetDeclaredSymbol获取该运算符的符号时,得到的是SourceUserDefinedOperatorSymbol;但在实际代码中使用这个运算符(比如bool a = 3 > 5;)时,通过GetSymbolInfo拿到的却是SynthesizedIntrinsicOperatorSymbol。我需要让声明处获取的符号和使用处保持一致,也就是把SourceUserDefinedOperatorSymbol转换为对应的SynthesizedIntrinsicOperatorSymbol。

我的测试代码如下:

bool a = 3 > 5;
namespace System
{
    public struct Int32
    {
        public static extern bool operator >(int a, int b);
    }
    public struct Boolean { }
}

我现在有一个方法框架,需要完成这个转换逻辑:

public static IMethodSymbol GetDeclaredSymbol (OperatorDeclarationSyntax ods)
{
    IMethodSymbol opSym = model.GetDeclaredSymbol(ods) ?? throw new Exception("Symbol not found");
    if (opSym is SourceUserDefinedOperatorSymbol)
    {
        // 需要在这里实现转换逻辑
    }
    return opSym;
}

解决方案思路

核心原因是你自定义的System.Int32运算符其实是在覆盖Roslyn内置的intrinsic运算符,所以我们可以通过查找编译环境中内置的Int32运算符符号来实现转换。具体步骤如下:

  1. 从当前编译上下文获取系统内置的System.Int32类型符号
  2. 根据自定义运算符的类型(比如>对应op_GreaterThan)找到对应的内置运算符方法
  3. 返回这个内置运算符符号,它就是SynthesizedIntrinsicOperatorSymbol类型

完整实现代码

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

public static IMethodSymbol GetDeclaredSymbol(OperatorDeclarationSyntax ods, SemanticModel model)
{
    IMethodSymbol opSym = model.GetDeclaredSymbol(ods) 
        ?? throw new InvalidOperationException("Failed to retrieve declared operator symbol");
    
    if (opSym is SourceUserDefinedOperatorSymbol userDefinedOp)
    {
        // 获取编译环境中的内置System.Int32类型
        var intrinsicIntType = model.Compilation.GetTypeByMetadataName("System.Int32");
        if (intrinsicIntType == null)
            throw new InvalidOperationException("System.Int32 type not found in current compilation");
        
        // 根据运算符类型映射到标准元数据名称
        string operatorMetadataName = userDefinedOp.MethodKind switch
        {
            MethodKind.GreaterThan => WellKnownMemberNames.GreaterThanOperator,
            MethodKind.LessThan => WellKnownMemberNames.LessThanOperator,
            MethodKind.Equality => WellKnownMemberNames.EqualityOperator,
            // 可以根据需要扩展其他运算符类型
            _ => throw new NotSupportedException($"Operator kind {userDefinedOp.MethodKind} is not supported")
        };
        
        // 查找对应的内置运算符符号
        var intrinsicOperator = intrinsicIntType.GetMembers(operatorMetadataName)
            .OfType<IMethodSymbol>()
            .FirstOrDefault(method => 
                method.Parameters.Length == 2 &&
                method.Parameters[0].Type.Equals(intrinsicIntType) &&
                method.Parameters[1].Type.Equals(intrinsicIntType));
        
        // 找到则返回内置符号,否则返回原符号
        return intrinsicOperator ?? opSym;
    }
    
    return opSym;
}

代码说明

  • 获取内置Int32类型:通过Compilation.GetTypeByMetadataName获取的是Roslyn内置的Int32符号,而非你自定义的那个,这是转换的关键。
  • 运算符名称映射:使用WellKnownMemberNames中的常量来避免硬编码运算符的元数据名称,保证兼容性。
  • 参数校验:通过检查参数数量和类型,确保找到的是我们需要的那个运算符重载(对于Int32的比较运算符来说,通常只有一个符合条件的重载)。

这样处理后,当你调用这个方法获取自定义运算符声明处的符号时,返回的就会和代码中使用该运算符时获取的SynthesizedIntrinsicOperatorSymbol完全一致了。

内容的提问来源于stack exchange,提问作者trinalbadger587

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 13:22:48