最后,我能够使用多种技术解决我的问题。以下是我所做的,以防这对其他人有所帮助:
-
我与相关方进行了交谈,我们同意在以下情况下不需要使用显式输入:
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
-
因此,可读性较差且需要显式键入的情况如下:
Dim X4 = SomeMethod() 'Cannot infer X4's type without peeking or using Go To Definition
-
然后,我使用以下正则表达式查找所有此类实例:
Dim \w+ = (?!(New|\d|"|DirectCast))
-
我只剩下几百个实例,但要逐个检查它们仍然是一项艰巨的任务,找到RHS方法的类型,然后在LHS上键入它。所以我搜索了VS扩展并发现
Visual Commander
这让我们可以用C#或VB编写宏,猜猜看是什么。NET并使用Roslyn API以我们想要的任何方式操纵代码元素。因此,我安装了它,在玩了一段时间后,我能够编写以下宏,该宏提取RHS方法的返回类型,然后将其注入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;
}
-
这个剧本为我起了很大的作用。然后,我可以将快捷键分配给
GoToFindResult1NextLocation
和
GoToFindResult1PrevLocation
命令并遍历查找结果,修复我需要的结果。
-
通过循环解决方案中的所有文件并自动修复所有这些行,可以改进此代码以提供更高的自动化程度,但我认为对将要更改的行进行更多控制是明智的。
最后,我能够在几分钟内解决整个解决方案中的所有问题。此外,我还对Roslyn API的结构了解了很多。