在类上实现接口作为代码修复的一部分

时间:2015-12-08 12:29:23

标签: c# interface roslyn

作为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为false,我需要将接口添加到基本类型列表中。 我已经尝试了t.BaseTypes.Add(...),而且我有点卡住了 - 不知道如何构建正确的参数。

这是正确的方法吗?

2 个答案:

答案 0 :(得分:3)

通过检查基础符号的AllInterfaces属性,检查类声明是否实现了接口可以更优雅的方式完成。

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

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

对于SyntaxFactory的修改,您始终可以参考RoslynQuoter

答案 1 :(得分:1)

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

代码如下所示:

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;