如何确定分部方法没有实现

本文关键字:实现 方法 何确定 | 更新日期: 2023-09-27 17:57:56

给定情况:

partial class Test
{
    partial void FooBar();
}
partial class Test
{
    public void Foo()
    {
        FooBar();
    }
}

现在,从FooBar()调用中获得SymbolInfo会给我一个IMethodSymbol,其中PartialDefinitionPart == nullPartialImplementationPart == null。是否有办法确定不存在部分实施?

如何确定分部方法没有实现

PartialDefinitionPart的XML文档中说:

如果这是部分方法实现部分,则返回相应的定义部分。否则为空。

PartialImplementationPart:

如果这是一个没有正文的分部方法声明,并且该方法为使用body实现,返回该实现定义。否则无效的

这意味着,如果您正在调用一个具有实现的分部方法,那么它的符号将具有非-nullPartialImplementationPart。有趣的是,似乎没有一种简单的方法来确定一个方法是否是部分的。

方法声明必须为

  1. 具有partial修饰符(MethodDeclarationSyntax.Modifiers
  2. 和(基于svicks答案)都没有IMethodSymbol.PartialDefinitionPart
  3. 或者CCD_ 13在没有实现的情况下是部分的

下面的代码演示了如何在给定的解决方案中找到所有部分方法,而不需要实现:

foreach (var project in solution.Projects)
{
    foreach (var document in project.Documents)
    {
        var methods = document
            .GetSyntaxRootAsync().Result
            .DescendantNodes()
            .OfType<MethodDeclarationSyntax>()
            .ToList();
        var semanticModel = document.GetSemanticModelAsync().Result;
        foreach (var method in methods)
        {
            if (method.Modifiers.All(m => m.ValueText != "partial"))
                continue;
            var methodSymbol = semanticModel.GetDeclaredSymbol(method);
            if (methodSymbol.PartialDefinitionPart == null 
                && methodSymbol.PartialImplementationPart == null)
            {
                // found partial method without an implementation!
            }
        }
    }
}

由于您已经有了一个方法符号,并且知道您的方法是分部的,这当然有点过头了,但我想展示如何在没有它们是分部的先验知识的情况下找到未实现的分部方法

当我试图查找该方法时,我自己正在使用IMethodSymbol中的语法进行编码,并在这个roslyn github问题[1]中找到了一个实现。那个版本对我不起作用,因为我发现DeclaringSyntaxReferences只包含一个项,即使分部方法有body。我是这样修复的:

    public static bool IsPartialMethod(this IMethodSymbol method, out bool hasEmptyBody)
    {
        if (method.IsDefinedInMetadata())
        {
            hasEmptyBody = false;
            return false;
        }
        foreach (var reference in method.DeclaringSyntaxReferences)
        {
            var syntax = reference.GetSyntax();
            if (syntax.Kind() != SyntaxKind.MethodDeclaration)
                continue;
            var node = syntax as MethodDeclarationSyntax;
            if (!node.Modifiers.Any(SyntaxKind.PartialKeyword))
            {
                hasEmptyBody = false;
                return false;
            }
        }
        hasEmptyBody = method.PartialImplementationPart == null || method.PartialDefinitionPart != null;
        return true;
    }
    /// <returns>False if it's not defined in source</returns>
    public static bool IsDefinedInMetadata(this ISymbol symbol)
    {
        return symbol.Locations.Any(loc => loc.IsInMetadata);
    }

[1]https://github.com/dotnet/roslyn/issues/48#issuecomment-75641847