在类上迭代属性

本文关键字:属性 迭代 | 更新日期: 2023-09-27 18:27:57

我正试图编写一个T4模板来迭代项目文件夹(指定),并基于这些属性生成一个js文件。

我可以将我的第一个类文件作为ProjectItem返回(作为System.__ComObject返回)

我看到名称正确返回("MyReadModel.cs")

Public Class MyReadModel{
  Public string MyName { get; set; }
  public int MyAge { get; set;}
}

现在,我正努力将房产归还。该文件具有作为系统的FileCodeModel__ComObject。我找不到任何房产。

我试着做了以下事情:

projectItem.GetType().GetProperties()

但返回System.Reflection.PropertyInfo[0]

关于我哪里错了,有什么建议吗?它看起来像是一个com对象。。。也许这是错误的?

编辑:

参考:

http://www.olegsych.com/2008/07/t4-template-for-generating-sql-view-from-csharp-enumeration/

如何在VS2010中获得T4来迭代类';属性

代码:

<# Prepare(this); #>
<# foreach(ProjectItem pi in FindProjectItemsIn(CurrentProject.ProjectItems.Item("Commands"))) { #>
    <# WriteLine("found " + pi); #>
<# } #>
<#+    
static DTE Dte;
static Dictionary<string, ResultTypeInfo> ResultTypes;
static TextTransformation TT;
static Microsoft.CSharp.CSharpCodeProvider codeProvider = new Microsoft.CSharp.CSharpCodeProvider();
static Project CurrentProject;
IList<ProjectItem> FindProjectItemsIn(ProjectItem start) {
var list = new List<ProjectItem>();
FindProjectItemsIn(start, list);
return list;
}
static bool IsFolder1(ProjectItem item) {
    return (item.Kind == Constants.vsProjectItemKindPhysicalFolder);
}
void FindProjectItemsIn(ProjectItem start, IList<ProjectItem> list) {
foreach(ProjectItem item in start.ProjectItems) {
if(IsFolder1(item)) {
FindProjectItemsIn(item, list);
continue;
}
list.Add(item);
}
}

void Prepare(TextTransformation tt) {
TT = tt;
    // Get the DTE service from the host
    var serviceProvider = Host as IServiceProvider;
    if (serviceProvider != null) {
        Dte = serviceProvider.GetService(typeof(SDTE)) as DTE;
    }
var projectItem = Dte.Solution.FindProjectItem(Host.TemplateFile);
CurrentProject = projectItem.ContainingProject;
}

在类上迭代属性

为了获得给定源文件中包含的类/结构中的属性列表,您可以执行以下操作(使用CodeClass可以轻松获得类名等):

private IList<CodeProperty> GetProperties(string csFile)
{
  ProjectItem projectItem = TransformationContext.FindProjectItem(csFile);
  FileCodeModel codeModel = projectItem.FileCodeModel;
  var propertyList = new List<CodeProperty>();
  FindProperties(codeModel.CodeElements, propertyList);
  return propertyList;
}
private void FindProperties(CodeElements elements, IList<CodeProperty> properties)
{
  foreach (CodeElement element in elements)
  {
    CodeProperty property = element as CodeProperty;
    if (property != null)
    {
      properties.Add(property);
    } 
    FindProperties(element.Children, properties);
  }
}

您必须导入自己的Assembly才能通过反射访问类型属性。T4模板是在Visual Studio的上下文中执行的,这就是您无法访问项目类型的原因。

因此,使用assembly指令导入具有所需类型的程序集。可以使用宏定位程序集(例如$(SolutionDir))。然后,您可以导入命名空间并使用自己程序集中的类型。

可能是这样的:

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="$(SolutionDir)YourProject'bin'debug'YourAssembly.dll" #>
<#@ import namespace="YourNamespace" #>
<#
   Type typeInfo = typeof(yourType);
   foreach (PropertyInfo propertyInfo in yourType.GetProperties())
   {#>
      <#=propertyInfo.Name#>
<#}#>

强烈建议将其与Visual Studio 2010 SP 1(或更新版本)一起使用。以前的Visual Studio版本使用单个应用程序域来使用assembly指令加载程序集。因此,每次更新程序集时都必须重新启动Visual Studio。对于SP1,VS为每个T4转换使用一个新的appdomain。

private static IEnumerable<CodeElement> Flatten(CodeElements elements) {
    foreach (CodeElement2 child in elements) {
        yield return child;
        foreach (var i in Flatten( child.Children )) {
            yield return i;
        }
    }
}

var imports = Flatten( fileCodeModel.CodeElements )
                .Where( i => i.Kind == vsCMElement.vsCMElementImportStmt )
                .Cast<CodeImport>();