【问题标题】:Implement interface on class as part of a Code Fix在类上实现接口作为代码修复的一部分
【发布时间】:2015-12-08 22:11:34
【问题描述】:

作为 Roslyn 代码修复的一部分,我需要在一个类上实现一个接口,如果该类尚未实现它。

到目前为止,我能够检测到该类是否实现了接口:

var implements = false;
foreach (var b in t.BaseList.Types)
{
    var name = (b.Type as IdentifierNameSyntax)?.Identifier.ValueText;
    if (name == "IInterfaceName")
    {
        implements = true;
        break;
    }
}

现在,如果implements 为假,我需要将接口添加到基类型列表中。 我试过t.BaseTypes.Add(...),在这里我有点卡住了——不知道如何构造正确的参数。

这是正确的方法吗?

【问题讨论】:

  • 您可以使用 Linq 将其写为 bool implements = t.BaseList.Types.Select(b => b.Type).OfType<IdentifierNameSyntax>().Any(t => t.Identifier.ValueText == "IInterfaceName");

标签: c# interface roslyn


【解决方案1】:

可以通过检查底层符号的AllInterfaces 属性以更优雅的方式检查类声明是否实现接口。

c.SemanticModel.GetDeclaredSymbol(((ClassDeclarationSyntax)c.Node)).AllInterfaces

在您的代码修复中,您可以使用SyntaxFactory 来构建您的新树,然后修改文档以包含新构建的树。请注意,在 Roslyn 中,大部分内容都是不可变的,因此如果您刚开始调用 Add(...),它将返回您的对象的一个​​新实例,但不会更改文档中的那个实例。

至于SyntaxFactory的修改,可以随时参考RoslynQuoter

【讨论】:

    【解决方案2】:

    我最终找到了解决方案。首先,需要使用语义模型而不是语法树来确定接口是否已经实现——声明类型可能有多个分部类;在这种情况下,语法树只描述一个部分类。

    代码如下所示:

    var result = document.Project.Solution;
    
    var m = start.Parent.AncestorsAndSelf().OfType<MethodDeclarationSyntax>().First(); // the method to add
    var t = start.Parent.AncestorsAndSelf().OfType<ClassDeclarationSyntax>().First(); // the class type
    
    var semanticModel = await document.GetSemanticModelAsync(cancellationToken);
    var typeSymbol = semanticModel.GetDeclaredSymbol(t, cancellationToken);
    
    var i = typeSymbol.Interfaces; // the interfaces in the semantic model. Includes declared interfaces on all partial classes.
    
    // does the type implement the interface?
    var implements = false;
    foreach (var b in i)
    {
        if (b.Name == "IInterfaceName")
        {
            implements = true;
            break;
        }
    }
    
    if (!implements)
    {
        var newClass = t.AddBaseListTypes(SyntaxFactory.SimpleBaseType(SyntaxFactory.ParseTypeName("IInterfaceName")));
    
        // get root for current document and replace statement with new version
        var root = await document.GetSyntaxRootAsync(cancellationToken);
        var newRoot = root.ReplaceNode(t, newClass);
    
        // return new solution
        result = document.WithSyntaxRoot(newRoot).Project.Solution;
    }
    
    return result;
    

    【讨论】:

      猜你喜欢
      • 2015-01-05
      • 2017-06-22
      • 1970-01-01
      • 1970-01-01
      • 2014-03-05
      • 1970-01-01
      • 2014-09-03
      • 2011-02-06
      相关资源
      最近更新 更多