Roslyn分析器对象初始化器
问题描述:
我想有一个分析器检测所有对setter属性的调用,而不是在实现特定接口的对象的对象初始值设定项内部。我有点失去了如何检测,文档有点薄。我可以得到一个调用表达式,但是如何检查它是否在对象初始值设定项中?Roslyn分析器对象初始化器
任何想法?
答
要知道是否有任何特定的代码位于对象初始值设定项中,您可以简单地查找祖先的任何类型为InitializerExpressionSyntax
的节点。
var initializer = node.Ancestors().OfType<InitializerExpressionSyntax>.FirstOrDefault();
要知道任何特定的代码是一个分配给一个属性的setter,你必须做一些更多的工作。您需要询问SemanticModel
的符号分配给AssignmentExpressionSyntax
。您的分析仪应该可以从其参数/上下文访问正确的SemanticModel
和SyntaxTree
。
SemanticModel model = ...;
AssignmentExpressionSyntax assignment = ...; // find the assignment
var symbol = model.GetSymbolInfo(assignment).Symbol as IMethodSymbol;
if (symbol?.MethodKind == MethodKind.PropertySet) { ... }
要知道对象是否实现了特定的接口,您将需要找到该对象的符号。您可以通过查找属性设置符号的包含符号链来找到它。您还可以通过查找ObjectCreationExpressionSyntax
来找到该对象的符号,该符号应该是您已拥有的InitializerExpressionSyntax
的父代或祖先。
一旦你有了那个创建节点,你可以再次询问SemanticModel
。使用GetTypeInfo
方法获取表达式的类型(正在构造的类型/符号),而不是构造函数的符号。
var creation = initializer.Ancestors().OfType<ObjectCreationSyntax>().FirstOrDefault();
var createdType = model.GetTypeInfo(creation).Type as INamedTypeSymbol;
现在,您只需要知道该类型是否实现接口。
首先,您需要一个接口类型的符号。一个快速的方法是使用CLR元数据名称查找它。
var interfaceType = model.Compilation.GetTypeByMetadataName("MyNamspace.MyInterfaceType");
这部分通常在分析仪的初始化做一次,这样你就不必继续寻找它,一遍又一遍。
现在你已经拥有了所有你需要的东西来发现被构造的类型是否实现了接口。
if (createdType.AllInterfaces.Contains(interfaceType)) { ... }
使用Syntax Visualizer来查看语法树的外观。 – SLaks