2016-09-26 94 views
1

使用反射,一類或子類的INamedTypeSymbol它非常簡單,以確定對象是否是給定類的,使用這樣的事情:羅斯林 - 是一個給定類型

(t == typeof(MyClass)) || (typeof(MyClass).IsAssignableFrom(t)) 

我想想出如何在Roslyn的代碼分析API中做同樣的事情。我正在使用這樣的循環,試圖在解決方案中查找所有局部變量聲明。

foreach (var decl in rootNode.DescendantNodes().OfType<LocalDeclarationStatementSyntax>()) 
       { 
        var symbolInfo = semanticModel.GetSymbolInfo(decl.Declaration.Type); 
        var typeInfo = symbolInfo.Symbol as INamedTypeSymbol; 
        if (typeInfo == null) 
        { 
         continue; 
        } 
        // WHAT DO? 

       } 

我最終試圖建立它們是給定類型的,或者是給定類型的子類的所有變量的列表。很容易看到我可以如何將變量類型的名稱與我正在尋找的已知類型的名稱進行比較 - 但我也需要處理子類的情況。

有沒有一個強大的方式與Roslyn做到這一點?

+0

如果你想處理泛型,這變得非常複雜。 – SLaks

回答

0

我有一個幫手,從前一段時間開始檢查這個。我最近還沒有和Roslyn和解過,所以有人可能不得不驗證這是否仍然是一個合適的解決方案。

基本上,一旦你有了INamedTypeSymbol,你可以檢查它的BaseType屬性的基類和它的AllInterfaces屬性爲它實現的所有接口。我不記得後者是在語義層面還是句法層面上工作(例如,它是否爲您提供了層次結構中特定類型實現的接口或者所有接口)。名字暗示後者。

public static bool ImplementsInterfaceOrBaseClass(this INamedTypeSymbol typeSymbol, Type typeToCheck) 
{ 
    if (typeSymbol == null) 
    { 
     return false; 
    } 

    if (typeSymbol.MetadataName == typeToCheck.Name) 
    { 
     return true; 
    } 

    if (typeSymbol.BaseType.MetadataName == typeToCheck.Name) 
    { 
     return true; 
    } 

    foreach (var @interface in typeSymbol.AllInterfaces) 
    { 
     if (@interface.MetadataName == typeToCheck.Name) 
     { 
      return true; 
     } 
    } 

    return false; 
} 
+0

我不確定這些「名稱」檢查是否有效 - 它們通常不是完全合格的名稱。 –

+0

像「FullName」這樣的其他屬性會更合適嗎?我並不十分熟悉它的複雜性。我看了一下你詳細的擴展方法,但看起來像一個通用的版本可用於許多不同類型的符號,並可能在這裏有點矯枉過正。 –

2

您可以callcompilation.ClassifyConversion(source, target)和檢查結果的Kind是否ConversionKind.ImplicitReference

+0

ConversionKind是內部的。 –

+0

@AlexZhukovskiy:http://source.roslyn.io/#Microsoft.CodeAnalysis.CSharp/Binder/Semantics/Conversions/Conversion.cs,426 – SLaks

5

在Roslyn IDE代碼庫中,我們使用this extension method。請注意,您需要注意是否僅包含基本類型或接口。另外,你關心泛型實例嗎?