我正在开发一个VS Extension,它需要知道文本光标当前位于哪个类成员(方法,属性等)。它还需要了解 parent (例如类(class),嵌套类(class)等)。它需要知道成员或类的类型,名称和行号。当我说“类型”时,我的意思是“方法”或“属性”,不一定是“.NET类型”。
目前,我在这里使用此代码:
public static class CodeElementHelper
{
public static CodeElement[] GetCodeElementAtCursor(DTE2 dte)
{
try
{
var cursorTextPoint = GetCursorTextPoint(dte);
if (cursorTextPoint != null)
{
var activeDocument = dte.ActiveDocument;
var projectItem = activeDocument.ProjectItem;
var codeElements = projectItem.FileCodeModel.CodeElements;
return GetCodeElementAtTextPoint(codeElements, cursorTextPoint).ToArray();
}
}
catch (Exception ex)
{
Debug.WriteLine("[DBG][EXC] - " + ex.Message + " " + ex.StackTrace);
}
return null;
}
private static TextPoint GetCursorTextPoint(DTE2 dte)
{
var cursorTextPoint = default(TextPoint);
try
{
var objTextDocument = (TextDocument)dte.ActiveDocument.Object();
cursorTextPoint = objTextDocument.Selection.ActivePoint;
}
catch (Exception ex)
{
Debug.WriteLine("[DBG][EXC] - " + ex.Message + " " + ex.StackTrace);
}
return cursorTextPoint;
}
private static List<CodeElement> GetCodeElementAtTextPoint(CodeElements codeElements, TextPoint objTextPoint)
{
var returnValue = new List<CodeElement>();
if (codeElements == null)
return null;
int count = 0;
foreach (CodeElement element in codeElements)
{
if (element.StartPoint.GreaterThan(objTextPoint))
{
// The code element starts beyond the point
}
else if (element.EndPoint.LessThan(objTextPoint))
{
// The code element ends before the point
}
else
{
if (element.Kind == vsCMElement.vsCMElementClass ||
element.Kind == vsCMElement.vsCMElementProperty ||
element.Kind == vsCMElement.vsCMElementPropertySetStmt ||
element.Kind == vsCMElement.vsCMElementFunction)
{
returnValue.Add(element);
}
var memberElements = GetCodeElementMembers(element);
var objMemberCodeElement = GetCodeElementAtTextPoint(memberElements, objTextPoint);
if (objMemberCodeElement != null)
{
returnValue.AddRange(objMemberCodeElement);
}
break;
}
}
return returnValue;
}
private static CodeElements GetCodeElementMembers(CodeElement codeElement)
{
CodeElements codeElements = null;
if (codeElement is CodeNamespace)
{
codeElements = (codeElement as CodeNamespace).Members;
}
else if (codeElement is CodeType)
{
codeElements = (codeElement as CodeType).Members;
}
else if (codeElement is CodeFunction)
{
codeElements = (codeElement as CodeFunction).Parameters;
}
return codeElements;
}
}
因此,这目前可行,如果我调用GetCodeElementAtCursor,我将获得该成员及其 parent 。 (这是一个很旧的代码,但是我相信我最初是从Carlos' blog捕获它并从VB移植的)。
我的问题是,当我的扩展名用在非常大的代码上时(例如,自动生成的文件有几千行),它会使VS爬行。几乎无法使用。运行探查器显示热线是
private static List<CodeElement> GetCodeElementAtTextPoint(CodeElements codeElements, TextPoint objTextPoint)
{
foreach (CodeElement element in codeElements)
{
...
/*-->*/ if (element.StartPoint.GreaterThan(objTextPoint)) // HERE <---
{
// The code element starts beyond the point
}
/*-->*/ else if (element.EndPoint.LessThan(objTextPoint)) // HERE <----
{
// The code element ends before the point
}
else
{
...
var memberElements = GetCodeElementMembers(element);
/*-->*/ var objMemberCodeElement = GetCodeElementAtTextPoint(memberElements, objTextPoint); // AND, HERE <---
...
}
}
return returnValue;
}
因此,第三个显而易见,它是对自身的递归调用,因此,影响它的任何因素都会影响对其自身的调用。但是,前两个我不确定如何解决。
TextPoint.GreaterThan
和TestPoint.LessThan
方法的性能更好? 无论采用哪种方法,都只需要支持VS2015或更高版本即可。
谢谢!
更新:要回答Sergey的评论-确实确实是由
.GreaterThan
/.LessThan()
引起的。我已经分离了代码,并且减速肯定是在这些方法调用上发生的,而不是element.StartPoint
和element.EndPoint
的属性访问器。最佳答案
使用GetCursorTextPoint获得TextPoint之后,可以使用TextPoint.CodeElement属性查找当前代码元素:
EnvDTE.TextPoint p = GetCursorTextPoint(DTE);
foreach (EnvDTE.vsCMElement i in Enum.GetValues(typeof(EnvDTE.vsCMElement)))
{
EnvDTE.CodeElement e = p.CodeElement[i];
if (e != null)
System.Windows.MessageBox.Show(i.ToString() + " " + e.FullName);
}
关于c# - VS扩展: TextPoint.大于/小于对于大型文件来说非常慢,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45359130/