如何用Roslyn中的var替换字符串变量?

use*_*462 5 c# diagnostics roslyn

对于本地声明,例如:string a = string.Empty;

如何编写诊断程序以将其更改为:var a = string.Empty;

Nat*_*han 7

你不能.var关键字告诉编译器执行类型推断,并且只有var a;编译器没有足够的信息来推断类型.

但是,您可以执行以下任何操作

var a = new String();
var b = String.Empty;
var c = "";
Run Code Online (Sandbox Code Playgroud)

但这似乎比它的价值更多的努力.

编辑更新的请求:为什么要修改要使用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
Run Code Online (Sandbox Code Playgroud)

  • 原来的海报改变了这个问题,所以内森的回答再也没有意义了.(原来它很有道理.) (3认同)

rh0*_*005 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));
        }
    }
Run Code Online (Sandbox Code Playgroud)

这本质上是查看声明两侧的类型,如果它们相同(并且 RHS 还不是 var),则添加诊断。

这是代码修复的代码:

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);
    }
Run Code Online (Sandbox Code Playgroud)

这一点很好也很简单,只需从语法工厂获取 var 并将其切换出来即可。请注意,var 在 SyntaxFactory 中没有自己的静态方法,因此是按名称引用。