C# 分析器能否验证名称空间是否与文件位置正确匹配

C# 分析器能否验证名称空间是否与文件位置正确匹配,c#,roslyn,C#,Roslyn,通常在C#解决方案中命名名称空间,使其与项目的默认名称空间加上包含文件的任何子目录的名称相匹配 例如,名为Haddock.cs的文件位于名为Fish的目录中,默认名称空间(在VS中项目属性的第一个选项卡中)为Lakes,则该文件应包含以下内容 namespace Lakes.Fish { public class Haddock { } } 该项目包含一个很好的规则,用于验证类名是否与文件名匹配 是否有任何方法可以编写规则来验证命名空间名称是否正确?您可以使用Synta

通常在C#解决方案中命名名称空间,使其与项目的默认名称空间加上包含文件的任何子目录的名称相匹配

例如,名为
Haddock.cs
的文件位于名为
Fish
的目录中,默认名称空间(在VS中项目属性的第一个选项卡中)为
Lakes
,则该文件应包含以下内容

namespace Lakes.Fish
{
    public class Haddock
    {
    }
}
该项目包含一个很好的规则,用于验证类名是否与文件名匹配


是否有任何方法可以编写规则来验证命名空间名称是否正确?

您可以使用
SyntaxTreeContext
树.FilePath
SyntaxTreeAction
访问文件路径

获得路径后,就可以解析该路径,并将其与树中
NamesSpaceDeclarationSyntax
节点的所有名称进行比较

不幸的是,我认为目前没有办法获得项目的默认名称空间

这是我收集的一个快速样本,它能做到目前为止所能做的。处理/比较到名称空间的路径是基本的,可能有更好的方法,但这应该让您开始

public override void Initialize(AnalysisContext context)
{
    context.RegisterCompilationStartAction((compilationSyntax) =>
    {
        compilationSyntax.RegisterSyntaxTreeAction((syntaxTreeContext) =>
        {
            var semModel = compilationSyntax.Compilation.GetSemanticModel(syntaxTreeContext.Tree);
            var filePath = syntaxTreeContext.Tree.FilePath;

            if (filePath == null)
                return;

            var namespaceNodes = syntaxTreeContext.Tree.GetRoot().DescendantNodes().OfType<NamespaceDeclarationSyntax>();
            var parentDirectory = System.IO.Path.GetDirectoryName(filePath);

            // This will only work on windows and is not very robust.
            var parentDirectoryWithDots = parentDirectory.Replace("\\", ".").ToLower();

            foreach (var ns in namespaceNodes)
            {
                var symbolInfo = semModel.GetDeclaredSymbol(ns) as INamespaceSymbol;
                var name = symbolInfo.ToDisplayString();

                if (!parentDirectoryWithDots.EndsWith(name.ToLower().Trim()))
                {
                    syntaxTreeContext.ReportDiagnostic(Diagnostic.Create(
                       Rule, ns.Name.GetLocation(), parentDirectoryWithDots));
                }
            }
        });
    });
}
公共覆盖无效初始化(AnalysisContext上下文)
{
context.RegisterCompilationStartAction((编译语法)=>
{
compilationSyntax.RegisterSyntaxTreeAction((syntaxTreeContext)=>
{
var semModel=compilationSyntax.Compilation.GetSemanticModel(syntaxTreeContext.Tree);
var filePath=syntaxTreeContext.Tree.filePath;
if(filePath==null)
返回;
var namespaceNodes=syntaxTreeContext.Tree.GetRoot().degenantNodes().OfType();
var parentDirectory=System.IO.Path.GetDirectoryName(filePath);
//这将只在windows上工作,并且不是非常健壮。
var parentDirectoryWithDots=parentDirectory.Replace(“\\”,“).ToLower();
foreach(名称空间节点中的变量ns)
{
var symbolInfo=semModel.GetDeclaredSymbol(ns)作为InNamespaceSymbol;
var name=symbolInfo.ToDisplayString();
如果(!parentDirectoryWithDots.EndsWith(name.ToLower().Trim()))
{
syntaxTreeContext.ReportDiagnostic(Diagnostic.Create(
规则,ns.Name.GetLocation(),parentDirectoryWithDots));
}
}
});
});
}

这不会检查嵌套的
命名空间
声明。@很好地解决了问题,修复了。这仍然是错误的
ns.Name
将不包括外部块。@SLaks我更新了它以从SemanticModel中获取DisplayString,因此我认为现在应该可以处理这种情况了。谢谢!如果没有获取默认名称空间的方法,这是有限的,因此我添加了以下内容:。让我们希望它去某个地方吧!