2016-06-13 3 views
1
public void SomeMethod(string sampleString) 
{ var helloworld = sampleString; } 

Можно ли определить, является ли конкретный символ локальной переменной, полем класса или параметром метода? например если я вызову FindSymbolAtPosition на sampleString, смогу ли я сказать, что символ sampleString является параметром или переменной метода?Понимание/Получение типа символа?

EDIT: требование является то, что он должен работать с кодирования времени, для моего статического анализа кода, что им здание с Рослин

+0

время кодирования, для моего статического анализа кода инструмента, который им строится с roslyn. –

ответ

3

Вы не можете получить его непосредственно через свойство, потому что в var helloworld = sampleString;, заявление не имеет контекста, что если sampleString является параметром или нет. Но вы можете получить его из контекста метода, как это:

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 соответствует идентификатору.

UPDATE код, чтобы доказать, что он работает:

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 

EDIT База на комментарий @JeroenVannevel «s, мы можем использовать 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 
+0

да, но это вроде сделано через сравнение строк, мне больше интересно, если theres api или лучший способ сделать это, кроме сравнения по имени идентификатора. Спасибо хоть. –

+0

@KimKangIn Как человек может определить, является ли идентификатор параметром или нет? Сравнивая его с списком параметров, это означает, что сравнение имени идентификатора является правильным (и, вероятно, единственным) способом. –

+1

Если вы не хотите сравнивать по идентификатору (который я согласен не должен), вы можете просто получить символ параметра и сравнить его с символом локальной переменной. Используйте 'GetDeclaredSymbol' и' GetSymbolInfo' соответственно. –

-3

Вы можете различить ли вы имеете дело с классом области В.С. параметр метода или локальную переменную с ключевым словом this. Если у вас была строка поля класса, называемая sampleString, и вы хотели бы ссылаться на поле класса, а не на локальный параметр variable/method, тогда вы должны ссылаться на него с помощью this.sampleString. Вы должны ссылаться на локальный параметр variable/method как sampleString без ключевого слова (this). В терминах локальных переменных и параметров метода вы не можете иметь локальный параметр переменной и метода с тем же именем внутри одного и того же метода. С вашим кодом выше вы ссылаетесь на параметр sampleString.

+0

Это не то, что ОП просит – MickyD

+0

Я имею в виду косвенно, но я думаю, я не объяснил это достаточно ясно.Если вы используете FindSymbolAtPosition на sampleString в методе, он будет использовать его в параметре, а не в поле класса. Если он использовал FindSymbolAtPosition для this.sampleString, он будет использовать его в поле класса. Это предполагает, что существует локальная переменная и поле класса с именем sampleString. Обработанные параметры меняются в соответствии с локальными переменными, поэтому вы не можете объявить параметр и локальную переменную в том же методе с тем же именем. –

+0

В своем текущем фрагменте кода он, без сомнения, ссылается на параметр. Когда у вас есть параметр/локальная переменная в методе, который имеет то же имя, что и поле класса, и вы вызываете его без использования ключевого слова (this), вы всегда будете вызывать параметр/локальную переменную, а не поле класса. –

-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; 
    } 
} 
+1

Отражение полностью отделено от Рослина. Это не отвечает на вопрос. –

+0

@JeroenVannevel Это не было частью исходного вопроса. –

+1

Это всегда было помечено Roslyn, и метод, упомянутый в OP, также является частью Roslyn. –

0

Ее неправильно сравнивать идентификаторы синтаксисом или текстом, представьте себе, если IdentifierNameSyntax это имя MemberAccessExpressionSyntax и имеет тот же identifier как parameter, то вы бы неправильно сделать вывод, что это parameter, даже если это a member. Вы должны работать с SemanticModel, чтобы определить, что такое SymbolKind. Вы можете использовать SemanticModel.GetDeclaredSymbol в объявлениях и SemanticModel.GetSymbolInfo().Symbol об использовании символов. Как только у вас есть ISymbol, его легко определить. Имейте в виду, что разные символы имеют свои собственные «под-виды», например, ITypeSymbol имеет TypeKind свойство, которое определяет, является ли тип Class, Struct, Interface, Array и т. Д., Поэтому вы должны их проверить.

Смежные вопросы