首页 > 解决方案 > C#如何在 Roslyn 中检测 EvenHandler 订阅

问题描述

我正在使用 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是 Event ThresholdReached的订阅。如果有人知道怎么做,请帮助=)

标签: c#roslynroslyn-code-analysisroslynator

解决方案


在分析器中,您不能仅通过查看 a 来MethodDeclarationSyntax知道该方法是否转换为委托。因此,您无法知道(仅通过查看 a MethodDeclarationSyntax)该委托是否已传递给事件的 add 访问器。

首先,请记住 Roslyn 分析器只能查看当前程序集(项目)中的用法。如果您的方法在另一个程序集中转换为委托,则分析器无法看到这一点。

其次,记住

с.ThresholdReached += OnThresholdReached;

可以表示为

EventHandler handler = OnThresholdReached;
с.ThresholdReached += handler;

如果您只想检测第一种情况,您可以查看AssignmentExpressionSyntaxkind 的实例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
}

要查找该方法的源代码,请参阅https://stackoverflow.com/a/45362532/1403794


推荐阅读