C# Как я могу обнаружить подписку EvenHandler в Roslyn
Я пишу собственное правило анализатора с использованием Roslyn.
Я хочу найти метод, который является обработчиком для какого-либо события (через подписку). Как это:
public class Counter
{
public event EventHandler ThresholdReached;
}
public class TestEvent
{
public TestEvent()
{
Counter с = new Counter();
с.ThresholdReached += OnThresholdReached;
}
private void OnThresholdReached(object sender, EventArgs e)
{
}
}
В моей реализации это выглядит так:
private static void HandleMethodDeclaration(SyntaxNodeAnalysisContext context)
{
MethodDeclarationSyntax methodDeclaration = (MethodDeclarationSyntax)context.Node;
if (methodDeclaration.Identifier.IsMissing)
{
return;
}
IMethodSymbol methodSymbol = context.SemanticModel.GetDeclaredSymbol(methodDeclaration);
}
Я не знаю, как определить, что OnThresholdReached является подпиской на событие ThresholdReached. Если кто-то знает, как это сделать, помогите пожалуйста =)
1 ответ
В анализаторе вы не можете знать только, глядя на MethodDeclarationSyntax
независимо от того, преобразуется ли этот метод в делегат или нет. Из-за этого вы не можете знать (только глядя на MethodDeclarationSyntax
) передается ли этот делегат добавителю доступа события или нет.
Прежде всего, помните, что анализатор Roslyn может видеть только использования в текущей сборке (проекте). Если ваш метод преобразован в делегат в другой сборке, анализатор не сможет увидеть это.
Во-вторых, помните, что
с.ThresholdReached += OnThresholdReached;
может быть выражено как
EventHandler handler = OnThresholdReached;
с.ThresholdReached += handler;
Если вы хотите обнаружить только первый случай, вы можете посмотреть на AssignmentExpressionSyntax
примеры добрых SyntaxKind.AddAssignmentExpression
и проанализировать их.
Если вы хотите обнаружить все случаи, когда группа методов преобразуется в делегат, вам необходимо просмотреть все экземпляры типа SimpleNameSyntax
и проанализируйте их следующим образом:
void Analyze(SyntaxNodeAnalysisContext context)
{
var node = context.Node as SimpleNameSyntax;
// we're only interested in delegates
var type = context.SemanticModel.GetTypeInfo(node, context.CancellationToken).ConvertedType;
if (type == null || type.TypeKind != TypeKind.Delegate)
{
return;
}
// we're only interested in methods from the current assembly
var symbol = context.SemanticModel.GetSymbolInfo(node, context.CancellationToken).Symbol;
if (symbol == null ||
symbol.Kind != SymbolKind.Method ||
!symbol.ContainingAssembly.Equals(context.SemanticModel.Compilation.Assembly))
{
return;
}
// now you know symbol is a method in the same assembly, that is converted to a delegate
}
Чтобы найти исходный код для этого метода, см. /questions/28913148/roslyn-poluchaet-metod-deklaratsii-ot-invocation/28913156#28913156.