将所有变量更改为显式类型

4

(没有意图在编码风格上引发宗教战争,我只需要解决手头的问题)

我刚被要求更改整个解决方案中所有变量声明为显式类型,即像以下任何内容:

Dim Result = 3 + 5

应该转换为:

Dim Result As Integer = 3 + 5

显然,这不能通过查找/替换甚至正则表达式来完成。我想到的另外两种可能性是:
  1. Resharper:我刚刚发现它只能用于C#,而不能用于VB.NET。
  2. 宏:自从VS2012以后已经被删除了(这对我来说是一个新闻)。
有没有其他的自动化这个繁琐工作的方法?这个解决方案包含数十万行代码,所以手动完成不是一个选择。
这是针对VS2017 Community的。

2
是的,所以在你的项目中设置 Option Explicit 并一一解决错误。否则你将需要一个静态代码分析工具来重写源文件。 - CodeCaster
“Option Strict”已经在解决方案的所有项目中启用。这与问题没有太大关系。存在一些奇怪的对象实例化用法,例如Dim hwnd = New WindowInteropHelper(w).Handle以及其他类似LINQ调用的内容,这使得问题变得非常困难。 - dotNET
1
你尝试将警告设置“隐式类型,假定为对象”更改为错误了吗?使用此设置,您可以获取有关那些未声明As规范的变量的错误列表,并通过Ctrl+Shift+F12进行导航。 - Steve
1
你还需要加上 Option Infer = NO。 - Steve
@Steve:谢谢。听起来很有前途。让我在午餐休息后深入挖掘一下。 - dotNET
显示剩余5条评论
1个回答

1

最终我通过多种技术解决了我的问题。以下是我所做的,希望能对其他人有所帮助:

  1. I talked to the concerned parties and we agreed that we do not need to use Explicit Typing in the following scenarios:

    Dim X1 = 45 + 43 'Type can be inferred by the reader easily
    Dim X2 = DirectCast(obj, DataReader) 'Type explicitly mentioned on RHS        
    Dim X3 = New SomeClass() 'Type explicitly mentioned on RHS
    
  2. So the case which was really less readable and where Explicit Typing was needed was the following:

    Dim X4 = SomeMethod() 'Cannot infer X4's type without peeking or using Go To Definition
    
  3. I then used the following RegEx to locate all such instances:

    Dim \w+ = (?!(New|\d|"|DirectCast))
    
  4. I was left with only a few hundred instances, but it was still a huge task to go through them individually, finding the type of RHS method and then typing it on the LHS. So I searched through VS extensions and found Visual Commander that allows us to write, guess what, macros in C# or VB.NET and use Roslyn API to manipulate code elements in any way we want. So I installed it and after playing with it for some time, I was able to write the following macro which extracts the return type of the RHS method and then injects it to the LHS:

    using Microsoft.CodeAnalysis;
    using Microsoft.CodeAnalysis.Text;
    using System.Linq;
    using Microsoft.CodeAnalysis.VisualBasic;
    using Microsoft.CodeAnalysis.VisualBasic.Syntax;
    
    public class C : VisualCommanderExt.ICommand
    {
      public void Run(EnvDTE80.DTE2 DTE, Microsoft.VisualStudio.Shell.Package package)
      {
        serviceProvider = package as System.IServiceProvider;
        Microsoft.VisualStudio.Text.Editor.IWpfTextView textView = GetTextView();
    
        Microsoft.VisualStudio.Text.SnapshotPoint caretPosition = textView.Caret.Position.BufferPosition;
        Microsoft.CodeAnalysis.Document document = caretPosition.Snapshot.GetOpenDocumentInCurrentContextWithChanges();
        Microsoft.CodeAnalysis.VisualBasic.Syntax.LocalDeclarationStatementSyntax invocationExpressionNode =
            document.GetSyntaxRootAsync().Result.FindToken(caretPosition).Parent.AncestorsAndSelf().
                OfType<Microsoft.CodeAnalysis.VisualBasic.Syntax.LocalDeclarationStatementSyntax>().FirstOrDefault();
    
        if (invocationExpressionNode != null)
        {
          Microsoft.CodeAnalysis.SemanticModel semanticModel = document.GetSemanticModelAsync().Result;
    
          var VD = invocationExpressionNode.ChildNodes().FirstOrDefault(c => c.IsKind(SyntaxKind.VariableDeclarator));
    
          if (VD != null)
          {
            var EV = VD.ChildNodes().FirstOrDefault(c => c.IsKind(SyntaxKind.EqualsValue) || c.IsKind(SyntaxKind.EqualsExpression));
    
            if (EV != null)
            {
              object IE = EV.ChildNodes().FirstOrDefault(c => c.IsKind(SyntaxKind.InvocationExpression));
    
              if (IE != null)
              {
                Microsoft.CodeAnalysis.IMethodSymbol methodSymbol =
                  semanticModel.GetSymbolInfo((InvocationExpressionSyntax)IE).Symbol as Microsoft.CodeAnalysis.IMethodSymbol;
    
                string TypeName = methodSymbol.ReturnType.ToString();
                string ToInsert = " As " + TypeName;
                textView.TextBuffer.Insert(((InvocationExpressionSyntax)IE).SpanStart - 2, ToInsert);
              }
            }
          }
        }
      }
    
      private Microsoft.VisualStudio.Text.Editor.IWpfTextView GetTextView()
      {
        Microsoft.VisualStudio.TextManager.Interop.IVsTextManager textManager =
            (Microsoft.VisualStudio.TextManager.Interop.IVsTextManager)serviceProvider.GetService(
                typeof(Microsoft.VisualStudio.TextManager.Interop.SVsTextManager));
        Microsoft.VisualStudio.TextManager.Interop.IVsTextView textView;
        textManager.GetActiveView(1, null, out textView);
        return GetEditorAdaptersFactoryService().GetWpfTextView(textView);
      }
    
      private Microsoft.VisualStudio.Editor.IVsEditorAdaptersFactoryService GetEditorAdaptersFactoryService()
      {
        Microsoft.VisualStudio.ComponentModelHost.IComponentModel componentModel =
            (Microsoft.VisualStudio.ComponentModelHost.IComponentModel)serviceProvider.GetService(
                typeof(Microsoft.VisualStudio.ComponentModelHost.SComponentModel));
        return componentModel.GetService<Microsoft.VisualStudio.Editor.IVsEditorAdaptersFactoryService>();
      }
    
      private System.IServiceProvider serviceProvider;
    }
    
  5. This script did the heavy-lifting for me. I was then able to assign shortcut keys to GoToFindResult1NextLocation and GoToFindResult1PrevLocation commands and traverse through the Find Results, fixing the ones that I needed to.

  6. This code can be improved to provide even more automation by looping through all files in the solution and fix all these lines automatically, but I thought it would be wise to have more control over the lines that are going to be changed.

最终,我能够在几分钟内解决整个解决方案中出现的所有情况。此外,我还学到了有关Roslyn API结构的很多知识。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接