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

本文关键字:代码 一部分 实现 接口 | 更新日期: 2023-09-27 18:26:14

作为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(...),但这里我有点卡住了——不知道如何构造正确的参数。

这是正确的方法吗?

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

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

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

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

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

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

代码如下:

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;