2014-04-14 10 views
2

CodeModel是發現Visual Studio內部代碼的強大工具。我們將VS2013的CodeModel與T4結合使用來生成我們3層體系結構中大部分乏味的代碼。什麼是使用Visual Studio的代碼模型來查找類的更快方法?

我發現什麼是以下幾點:

我們有2個項目,假設A和B,其中一個(A)有(B)的參考。在項目A中,我們僅使用此項目中的模型類來生成模型的擴展。這些類在項目B中使用了幾個類。下面是這些類中的一個的示例。

using Common.Library; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Linq; 

namespace Projecten.Model.DataContracts.Statistiek 
{ 
    [DataObject] 
    [CustomResultClass("FactuurStatistiek")] 
    public partial class FactuurStatistiek : BaseStatistiek 
    { 
     public FactuurStatistiek Copy() 
     { 
      FactuurStatistiek copy = new FactuurStatistiek(); 

      copy.AddRange(this); 

      return copy; 
     } 
    } 
} 

我們已經與其中的[CustomResultClass]屬性被用於代碼生成2個屬性的裝飾類。

問題是,當我們在項目A中找到此類的CodeModel時,這些屬性不可用。我寫了一個搜索例程來搜索整個解決方案。下面的代碼:

public CodeType CodeType 
    { 
     get 
     { 
      if (m_CodeType == null) 
      { 
       m_CodeType = GetCodeType(); 
      } 

      return m_CodeType; 
     } 
    } 

    /// <summary> 
    /// Get the CodeType for the property 
    /// </summary> 
    private CodeType GetCodeType() 
    { 
     string name = Name; 
     CodeType codeType = null; 

     if (name == "FactuurStatistiek") 
     { 
      codeType = FindCodeType(CodeProperty.Type.AsFullName); 
     } 

     if (codeType == null) 
     { 
      CodeTypeRef codeTypeRef = CodeProperty.Type; 

      if (codeTypeRef.CodeType.IsCodeType) 
      { 
       codeType = codeTypeRef.CodeType; 
      } 

      if (codeType == null) 
      { 
       if (string.IsNullOrEmpty(CodeProperty.Type.AsFullName)) 
       { 
        codeType = CodeModel.CodeTypeFromFullName(CodeProperty.Type.AsString); 
       } 
       else 
       { 
        codeType = CodeModel.CodeTypeFromFullName(CodeProperty.Type.AsFullName); 
       } 
      } 
     } 

     return codeType; 
    } 

    private CodeType FindCodeType(string fullName) 
    { 
     CodeType codeType = null; 

     foreach (Project project in Metadata.Dte.Solution.Projects) 
     { 
      foreach (ProjectItem projectItem in project.ProjectItems) 
      { 
       codeType = RecurseProjectItems(projectItem.ProjectItems, fullName); 

       if (codeType != null) 
       { 
        return codeType; 
       } 
      } 
     } 

     return null; 
    } 

    private CodeType RecurseProjectItems(ProjectItems projectItems, string fullName) 
    { 
     CodeType codeType = null; 

     if (projectItems != null) 
     { 
      foreach (ProjectItem projectItem in projectItems) 
      { 
       if (projectItem.FileCodeModel != null) 
       { 
        codeType = RecurseCodeElements(projectItem.FileCodeModel.CodeElements, fullName); 

        if (codeType != null) 
        { 
         break; 
        } 
       } 

       codeType = RecurseProjectItems(projectItem.ProjectItems, fullName); 

       if (codeType != null) 
       { 
        break; 
       } 
      } 
     } 

     return codeType; 
    } 

    private CodeType RecurseCodeElements(CodeElements codeElements, string fullName) 
    { 
     CodeType codeType = null; 

     if (codeElements != null) 
     { 
      foreach (CodeElement codeElement in codeElements) 
      { 
       if (codeElement.Kind == vsCMElement.vsCMElementNamespace) 
       { 
        codeType = RecurseCodeElements(((CodeNamespace)codeElement).Members, fullName); 
       } 
       else if (codeElement.Kind == vsCMElement.vsCMElementClass) 
       { 
        string classFullName = ((CodeClass)codeElement).FullName; 

        if (((CodeClass)codeElement).FullName == fullName) 
        { 
         codeType = (CodeType)codeElement; 
        } 
       } 

       if (codeType != null) 
       { 
        break; 
       } 
      } 
     } 

     return codeType; 
    } 

此代碼工作正常,我們得到正確的CodeModel該類但代碼是非常,非常緩慢。我的猜測是,不僅遍歷所有的項目和項目使它慢,但我有這樣的感覺,在解決CodeModels發現類中的文本被解析。

我們應該如何改進搜索算法,使性能變得可以接受?

+0

沒有人對我有任何建議嗎? –

+0

我的建議是使用Roslyn來代替。 –

回答

3

你是正確的,一般的緩慢來自於解析文件的內容來生成CodeElements。我在我們的一個項目中解決了這個問題,通過限制哪些文件基於我正在搜索的基本啓發式進行處理。

你可以做一個簡單的String.Contains看看你在乎的東西是否在文件中,然後再解析它。這是一個簡單的例子,你需要最後執行FileCodeModel空檢查,因爲訪問該屬性需要進行一些分析。

var fileName = projectItem.FileNames[1]; 
var shouldProcessFile = File.Exsits(fileName) 
    && Path.GetExtension(fileName) == ".cs" 
    && File.ReadAllText(fileName).Contains("FactuurStatistiek") 
    && projectItem.FileCodeModel != null; 
if(shouldProcessFile) 
{ 
    codeType = RecurseCodeElements(projectItem.FileCodeModel.CodeElements, fullName); 
} 

上述方法是我爲我們所採用併爲之工作的方法。它仍然需要讀取項目中所有「.cs」文件的所有內容,並在內容中查找某些內容,但這比解析全部內容要快。

我想到的另一種方法是,如果您的項目中碰巧存在瘋狂數量的文件,但知道很少有真正需要解析的文件,則實際上是通過對文件第一行的註釋進行標記例如,如果你想要解析的文件的第一行是//PARSEME,那麼上面的代碼可以修改爲。

var fileName = projectItem.FileNames[1]; 
var shouldProcessFile = File.Exsits(fileName) 
    && Path.GetExtension(fileName) == ".cs" 
    && File.ReadLines(fileName).First().Contains("//PARSEME") 
    && File.ReadAllText(fileName).Contains("FactuurStatistiek") 
    && projectItem.FileCodeModel != null; 
if(shouldProcessFile) 
{ 
    codeType = RecurseCodeElements(projectItem.FileCodeModel.CodeElements, fullName); 
} 

由於添加了File.ReadLines(fileName).First().Contains("//PARSEME")的檢查它意味着你只有真正從讀取大多數文件的第一行你之前更昂貴的包含檢查。這當然是不利的,如果你添加新的文件,你需要記住標記可解析文件。

相關問題