Roslyn SemanticModel未报告const decimal初始化生成的静态构造函数
关于Roslyn未报告
const decimal隐式生成静态构造函数符号的疑问 提交Issue给Roslyn团队前,我先梳理下当前问题:const decimal并非真正的常量,而是静态成员,编译器会隐式生成静态构造函数初始化它,但Roslyn的SemanticModel实例并未报告该静态构造函数的符号,这和常规静态字段初始化等隐式生成静态构造函数的场景表现不一致。
示例代码
以下是使用Roslyn、Mono.Cecil和NUnit的测试代码:
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Mono.Cecil; using NUnit.Framework; namespace CSTool.UnitTests; public class RoslynScratch { private const string CODE = @"public static class Type1 { public const decimal Value = 1.0m; } public static class Type2 { public static readonly decimal Value = 1.0m; } public static class Type3 { public const int Value = 1; }"; private static readonly string[] s_netCoreReferences = [ typeof(object).Assembly.Location, Path.GetDirectoryName(typeof(object).Assembly.Location) + "\\System.Runtime.dll", ]; [Test] public void StaticCtor() { var syntaxTree = CSharpSyntaxTree.ParseText(CODE); var compilation = CSharpCompilation.Create("temp", [syntaxTree], s_netCoreReferences.Select(o => MetadataReference.CreateFromFile(o)).ToArray(), new CSharpCompilationOptions(OutputKind.NetModule)); Assert.That(compilation.GetDiagnostics(), Is.Empty); var model = compilation.GetSemanticModel(syntaxTree); var typeDecls = syntaxTree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>().ToList(); Assert.That(typeDecls, Has.Count.EqualTo(3)); AssertStaticCtor(model, typeDecls, "Type1", false); AssertStaticCtor(model, typeDecls, "Type2", true); AssertStaticCtor(model, typeDecls, "Type3", false); var ms = new MemoryStream(); var emitResult = compilation.Emit(ms); Assert.That(emitResult.Success, Is.True); Assert.That(emitResult.Diagnostics, Is.Empty); ms.Position = 0; var moduleDef = ModuleDefinition.ReadModule(ms, new ReaderParameters { InMemory = true, }); AssertStaticCtor(moduleDef, "Type1", true); AssertStaticCtor(moduleDef, "Type2", true); AssertStaticCtor(moduleDef, "Type3", false); } private void AssertStaticCtor(ModuleDefinition moduleDef, string typeName, bool expected) { var staticCtorDef = moduleDef.GetType(typeName).Methods.FirstOrDefault(o => o.Name == ".cctor"); Assert.That(staticCtorDef, expected ? Is.Not.Null : Is.Null); } private static void AssertStaticCtor(SemanticModel model, IList<ClassDeclarationSyntax> typeDecls, string typeName, bool expected) { var typeSymbol = model.GetDeclaredSymbol(typeDecls.First(o => o.Identifier.Text == typeName)); var staticCtorSymbol = typeSymbol.GetMembers().FirstOrDefault(o => o.Name == ".cctor"); Assert.That(staticCtorSymbol, expected ? Is.Not.Null : Is.Null); } }
断言结果对比
Roslyn SemanticModel 结果
AssertStaticCtor(model, typeDecls, "Type1", false); AssertStaticCtor(model, typeDecls, "Type2", true); AssertStaticCtor(model, typeDecls, "Type3", false);
Mono.Cecil ModuleDefinition 结果
AssertStaticCtor(moduleDef, "Type1", true); AssertStaticCtor(moduleDef, "Type2", true); AssertStaticCtor(moduleDef, "Type3", false);
代码验证显示,Roslyn未报告Type1的静态构造函数符号,但Mono.Cecil能检测到它确实存在。其他两个案例中两者结果一致,凸显该情况的特殊性。
请问这是设计如此,还是需要提交Bug?
补充说明
我还发现另一类Roslyn未报告实际存在方法符号的场景:
public class Derived: BaseImplementingInterfaceMethods, IInterface { }
其中BaseImplementingInterfaceMethods未显式实现IInterface,但已实现其所有方法,编译器会向Derived隐式注入接口的显式实现方法(委托给基类),这些方法也未被Roslyn报告。不过此内容与当前问题无关。
内容的提问来源于stack exchange,提问作者mark
相关产品推荐
相关产品推荐

