在类上实现接口作为代码修复的一部分
本文关键字:代码 一部分 实现 接口 | 更新日期: 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;