1
public void SomeMethod(string sampleString) 
{   var helloworld = sampleString; }

是否可以确定特定符号是局部变量、类字段还是方法的参数?例如,如果我在sampleString 上调用FindSymbolAtPosition,我能知道sampleString 符号是方法的参数还是变量?

编辑:要求它必须从编码时间开始工作,对于我使用 roslyn 构建的静态代码分析工具

4

4 回答 4

3

您不能直接通过属性获取它,因为在 中var helloworld = sampleString;,该语句没有 ifsampleString是否为参数的上下文。但是您可以像这样从方法的上下文中获取它:

static bool IsParameter(IdentifierNameSyntax name)
{
    SyntaxNode node = name;
    while (node != null && !(node is MethodDeclarationSyntax))
    {
        node = node.Parent;
    }

    var method = node as MethodDeclarationSyntax;
    if (method != null)
    {
        return method
            .ParameterList
            .Parameters
            .Any(p => p.Identifier.Text.Equals(name.Identifier.Text));
    }

    return false;            
}

.Parent用于获取变量的方法上下文,并检查是否有任何参数与.ParameterList标识符匹配。

更新代码以证明它正在工作:

SyntaxTree tree = CSharpSyntaxTree.ParseText(
    @"using System;
    using System.Collections;
    using System.Linq;
    using System.Text;

    namespace HelloWorld
    {
        class Program
        {
            static void Main(string i)
            {
                var j = ""1"";
                var k = i + j;
            }
        }
    }");

var root = (CompilationUnitSyntax)tree.GetRoot();
var ns = root.Members[0] as NamespaceDeclarationSyntax;
var cls = ns.Members[0] as ClassDeclarationSyntax;
var method = cls.Members[0] as MethodDeclarationSyntax;
var statement = method.Body.Statements[1] as LocalDeclarationStatementSyntax;
var variable = statement.Declaration.Variables[0];
var binary = variable.Initializer.Value as BinaryExpressionSyntax;
var vari = binary.Left as IdentifierNameSyntax;
var varj = binary.Right as IdentifierNameSyntax;
Console.WriteLine(IsParameter(vari));   //True
Console.WriteLine(IsParameter(varj));  //False

编辑基于@JeroenVannevel的评论,我们可以使用SemanticModel.GetSymbolInfo.

var compilation = CSharpCompilation.Create("test", new[] { tree });                
var semanticModel = compilation.GetSemanticModel(tree, true);
var symboli = semanticModel.GetSymbolInfo(vari);
var symbolj = semanticModel.GetSymbolInfo(varj);
//check symboli.Symbol.OriginalDefinition.Kind == SymbolKind.Parameter
于 2016-06-13T06:07:54.757 回答
0

通过语法或文本比较标识符是错误的,想象如果 theIdentifierNameSyntax是的名称MemberAccessExpressionSyntax并且与identifiera相同,那么即使它是 a parameter,你也会错误地断定它是 a 。您应该使用来确定 a是什么。您可以在声明和符号用法上使用。一旦你有了它就很容易确定它的种类。请记住,不同的符号有自己的“子种类”,例如具有确定类型是否为、、等的TypeKind属性,因此您应该检查它们。parametermemberSemanticModelSymbolKindSemanticModel.GetDeclaredSymbolSemanticModel.GetSymbolInfo().SymbolISymbolITypeSymbolClassStructInterfaceArray

于 2016-06-14T11:40:15.737 回答
-2

您可以使用以下代码获取类和参数的字段信息。但是请注意,方法字段的检测不可用。此代码使用反射来查询程序集信息并枚举和比较结果。

static class Program
{
    static void Main(string[] args)
    {

        SomeMethod("Hello, World!!!");

        Type testType = typeof(Program);
        FieldInfo[] fieldInfo = testType.GetFields();
        MethodInfo methodInfo = testType.GetMethod("SomeMethod");

        Console.WriteLine("Parameter type:{0}", TypeOfField(fieldInfo, methodInfo, "sampleString"));
        Console.WriteLine("Parameter type:{0}", TypeOfField(fieldInfo, methodInfo, "classField"));
        Console.WriteLine("Parameter type:{0}", TypeOfField(fieldInfo, methodInfo, "helloWorld"));
        Console.WriteLine("Parameter type:{0}", TypeOfField(fieldInfo, methodInfo, "nonexistentVariable"));

    }

    public static string classField = "Hello, World!!!";

    public static void SomeMethod(string sampleString)
    {
        string helloWorld = sampleString;
    }

    public static string TypeOfField(FieldInfo[] fieldInfo, MethodInfo methodInfo, string fieldName)
    {
        if (IsClassField(fieldInfo, fieldName))
        {
            return "Class Field";
        }
        else if (IsParameter(methodInfo, fieldName))
        {
            return "Parameter";
        }
        else
        {
            return "Cannot determine";
        }
    }

    private static bool IsClassField(FieldInfo[] fieldInfo, string classFieldName)
    {
        bool isClassField = false;

        foreach (var item in fieldInfo)
        {
            if (item.Name == classFieldName)
            {
                isClassField = true;
                break;
            }
        }
        return isClassField;
    }

    private static bool IsParameter(MethodInfo methodInfo, string parameterName)
    {
        bool isParameter = false;
        ParameterInfo[] paramInfo = methodInfo.GetParameters();
        foreach (var item in paramInfo)
        {
            if (item.Name == parameterName)
            {
                isParameter = true;
                break;
            }
        }
        return isParameter;
    }
}
于 2016-06-13T05:50:34.450 回答
-3

您可以使用关键字 this 区分您是在处理类字段还是方法的参数或局部变量。如果您有一个名为 sampleString 的类字段字符串,并且您想引用类字段而不是局部变量/方法参数,那么您可以使用 this.sampleString 来引用它。您可以将局部变量/方法参数称为不带关键字 (this) 的 sampleString。在局部变量和方法参数方面,您不能在同一个方法中拥有同名的局部变量和方法参数。使用上面的代码,您指的是 sampleString 参数。

于 2016-06-13T02:50:43.797 回答