作为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(...)
,而且我有点卡住了 - 不知道如何构建正确的参数。
这是正确的方法吗?
答案 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;