2014-04-22 26 views
4

對於本地聲明,如: string a = string.Empty;如何用Roslyn中的var替換字符串變量?

如何編寫診斷信息將其更改爲: var a = string.Empty;

+0

你的意思是沒有賦值只是聲明像'string a;'? –

+0

有什麼特別讓你失望?這對於StackOverflow問題來說太廣泛了。抓住SDK並查看示例。 –

+0

幸運的是,我碰巧在[這個項目](https://github.com/TheDutchDevil/Halcyon/tree/master/Source/FormattingFixes/TypeToVar)上創建了我自己的診斷工具,它已經實現了您感興趣的內容 –

回答

4

我已經把代碼補丁與診斷。 這裏的有趣的部分:

從ISyntaxNodeAnalyzer

AnalyzeNode實施
public void AnalyzeNode(SyntaxNode node, SemanticModel semanticModel, Action<Diagnostic> public void AnalyzeNode(SyntaxNode node, SemanticModel semanticModel, Action<Diagnostic> addDiagnostic, CancellationToken cancellationToken) 
    { 
     var localDeclaration = (LocalDeclarationStatementSyntax)node; 
     if (localDeclaration.Declaration.Type.IsVar) return; 
     var variable = localDeclaration.Declaration.Variables.First(); 
     var initialiser = variable.Initializer; 
     if (initialiser == null) return; 
     var variableTypeName = localDeclaration.Declaration.Type; 
     var variableType = semanticModel.GetTypeInfo(variableTypeName).ConvertedType; 
     var initialiserInfo = semanticModel.GetTypeInfo(variable.Initializer.Value); 
     var typeOfRightHandSideOfDeclaration = initialiserInfo.Type; 
     if (Equals(variableType, typeOfRightHandSideOfDeclaration)) 
     { 
      addDiagnostic(Diagnostic.Create(Rule, node.GetLocation(), localDeclaration.Declaration.Variables.First().Identifier.Value)); 
     } 
    } 

這基本上着眼於在聲明兩側的類型,如果它們是相同的(和RHS尚未變種)然後添加一個診斷。

而這裏的代碼修復代碼:

public async Task<IEnumerable<CodeAction>> GetFixesAsync(Document document, TextSpan span, IEnumerable<Diagnostic> diagnostics, CancellationToken cancellationToken) 
    { 
     var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); 
     var diagnosticSpan = diagnostics.First().Location.SourceSpan; 
     var declaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType<LocalDeclarationStatementSyntax>().First(); 
     return new[] { CodeAction.Create("Use var", c => ChangeDeclarationToVar(document, declaration, c)) }; 
    } 

private async Task<Document> ChangeDeclarationToVar(Document document, LocalDeclarationStatementSyntax localDeclaration, CancellationToken cancellationToken) 
    { 
     var root = await document.GetSyntaxRootAsync(cancellationToken); 
     var variableTypeName = localDeclaration.Declaration.Type; 
     var varTypeName = SyntaxFactory.IdentifierName("var").WithAdditionalAnnotations(Formatter.Annotation); 
     var newDeclaration = localDeclaration.ReplaceNode(variableTypeName, varTypeName);    
     var newRoot = root.ReplaceNode(localDeclaration, newDeclaration); 
     return document.WithSyntaxRoot(newRoot); 
    } 

這一點是好的,簡單,單純從語法工廠獲得var和切換出來。 請注意,var在SyntaxFactory中沒有自己的靜態方法,而是按名稱引用。

+0

正是我在找什麼......我唯一缺少的是: var root = await document.GetSyntaxRootAsync(cancellationToken); 這是用來幹什麼的? – user3500462

+0

這從文檔獲取語法的主要塊幷包含所有節點。然後使用較低的值替換目標節點,並使用新節點返回整個根。這就像返回一個節點列表,以便您可以訪問要替換的節點。 – rh072005

7

你不行。 var關鍵字告訴編譯器執行類型推斷,只有var a;編譯器沒有足夠的信息來推斷類型。

你可以做但下列任一

var a = new String(); 
var b = String.Empty; 
var c = ""; 

,但是這似乎是更多的努力比它的價值。

編輯更新的請求:爲什麼要修改所有要用var聲明的代碼?它編譯到相同的IL反正(平凡簡單的例子):

// var a = String.Empty; 
IL_0000: ldsfld  string [mscorlib]System.String::Empty 
IL_0005: pop 
// string b = String.Empty; 
IL_0006: ldsfld  string [mscorlib]System.String::Empty 
IL_000b: pop 
+0

'var'仍然是強類型的,編譯器需要在編譯時找出它是什麼類型。 – Nathan

+0

我意識到它後來只添加了我的評論,然後刪除。 –

+0

你完全誤解了這個問題。他問的是Roslyn語法API。 – SLaks

0

編譯器不能推斷從該類型。

您可能需要使用:

var a = ""; // compiler can see that is type `string`: 

,或者你可以這樣做:

string a; 
+0

原始海報問如何使用Roslyn API進行這種轉換。 –