设计时反射



是否有办法在设计时进行反射预编译?

我的意图是使用T4来吐出基于实现某些接口的类的自定义代码。我知道我可以调用反射,但我希望T4脚本在编译之前吐出额外的代码,否则我将需要编译两次代码,一次生成dll,两次让T4反映先前生成的dll并添加额外的脚手架。

是否有办法在设计时做反射?

有更好的方法吗?

实际上有一种基于Visual Studio Automation提供的CodeModel生成预构建代码的方法:项目接口提供了一个属性"CodeModel",它包含了该项目中所有模型工件的图。您可能希望遍历它以查找类、接口、属性等。在此基础上生成输出代码。

dandrejw已经提到了有形的t4编辑器。它有一个免费的模板画廊。有一个可重用的模板"有形的Visual Studio自动化助手",它应该对你的情况非常有帮助。使用此模板,您可以像这样解决问题:

这是t4模板中的代码,检测所有实现INotifyPropertyChanged的类。

<#
    // get a reference to the project of this t4 template
    var project = VisualStudioHelper.CurrentProject;
    // get all class items from the code model
    var allClasses = VisualStudioHelper.GetAllCodeElementsOfType(project.CodeModel.CodeElements, EnvDTE.vsCMElement.vsCMElementClass, false);
    // iterate all classes
    foreach(EnvDTE.CodeClass codeClass in allClasses)
    {
        // get all interfaces implemented by this class
        var allInterfaces = VisualStudioHelper.GetAllCodeElementsOfType(codeClass.ImplementedInterfaces, EnvDTE.vsCMElement.vsCMElementInterface, true);
        if (allInterfaces.OfType<EnvDTE.CodeInterface>()
                         .Any(i => i.Name == "INotifyPropertyChanged"))
        {
            #>Render your code here<#
        }
    }
#>

把你的输出代码放在代码片段说"Render your code here"的地方

对于没有心情尝试让T4 VisualStudioHelper模板工作的任何将来的读者,下面是一个自包含的模板,枚举当前项目中的所有类。它是在Visual Studio 2013中测试的,灵感来自于T4 Site上的代码

<#@ template  debug="true" hostSpecific="true" #>
<#@ output extension=".cs" #>
<#@ Assembly Name="System.Core" #>
<#@ assembly name="EnvDte" #>
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #> 
<#    
  foreach(var ns in GetNamespaceElements())
  {
    foreach(var cc in ns.Members.OfType<EnvDTE.CodeClass>())
    {
#>Render your code here<#
    }
  }
#>
<#+
  public IEnumerable<EnvDTE.CodeNamespace> GetNamespaceElements()
  {
    var visualStudio = (this.Host as IServiceProvider).GetService(typeof(EnvDTE.DTE))
                        as EnvDTE.DTE;
    var project = visualStudio.Solution.FindProjectItem(this.Host.TemplateFile)
                  .ContainingProject as EnvDTE.Project;
    var projItems = new List<EnvDTE.ProjectItem>();
    FillProjectItems(project.ProjectItems, projItems);
    var names = new HashSet<string>(projItems
      .Where(i => i.FileCodeModel != null)
      .SelectMany(i => i.FileCodeModel.CodeElements.OfType<EnvDTE.CodeElement>())
      .Where(e => e.Kind == EnvDTE.vsCMElement.vsCMElementNamespace)
      .Select(e => e.FullName));
    var codeNs = new List<EnvDTE.CodeNamespace>();
    FillCodeNamespaces(project.CodeModel.CodeElements.OfType<EnvDTE.CodeNamespace>(), codeNs);
    return codeNs.Where(ns => names.Contains(ns.FullName));
  }
  public void FillCodeNamespaces(IEnumerable<EnvDTE.CodeNamespace> parents, List<EnvDTE.CodeNamespace> all)
  {
    foreach (var parent in parents)
    {
      all.Add(parent);
      FillCodeNamespaces(parent.Members.OfType<EnvDTE.CodeNamespace>(), all);
    }
  }
  public void FillProjectItems(EnvDTE.ProjectItems items, List<EnvDTE.ProjectItem> ret)
  {
    if (items == null) return;
    foreach(EnvDTE.ProjectItem item in items)
    {
      ret.Add(item);
      FillProjectItems(item.ProjectItems, ret);
    }
  }
#>

我知道做到这一点的唯一方法是利用一些代码解析功能。我一时想不出一个办法来做那件事。我相信。net有一些实用程序可以做到这一点。

我不知道你的情况是什么,但通常不是阅读代码,你有一些集中的信息,无论是XML文件还是一些用于生成代码的UML图(甚至类图)。它简化了一些事情,使更改变得更容易,并让代码生成生成更改。看看Visual Studio的有形T4工具

相关内容

  • 没有找到相关文章

最新更新