遍历类的属性。

6
我正在尝试编写一个T4模板,以遍历指定的项目文件夹并基于这些属性生成一个js文件。
我能够返回我的第一个类文件作为ProjectItem(返回为System.__ComObject)。
我看到名称正确返回(“MyReadModel.cs”)。
Public Class MyReadModel{
  Public string MyName { get; set; }
  public int MyAge { get; set;}
}

现在我正在努力从中获取属性。 该文件有一个System.__ComObject作为FileCodeModel。 我找不到任何属性。
我尝试了以下操作:
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;
}

1
请不要在标题前加上“t4”等内容。这就是标签的作用。 - John Saunders
3个回答

4
为了获取给定源文件中包含的类/结构体中属性列表,您可以执行以下操作(通过使用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);
  }
}

0

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

因此,使用assembly-directive导入所需类型的程序集。您可以使用宏来定位您的程序集(例如$(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 SP1(或更新版本)进行此操作。以前的 Visual Studio 版本使用单个应用程序域来加载具有 assembly-directive 的程序集。因此,每次更新程序集时都必须重新启动 Visual Studio。使用 SP1 VS 为每个 T4 转换使用新的应用程序域。

我有什么遗漏吗?我想要迭代一个项目文件夹,返回项目项,获取类型并返回属性。如果我指定了类型,我可能会将其全部硬编码。 - nologo
使用.NET反射会更容易。由您的方法返回的ComObject不能被.NET反射使用,因为它不是.NET类型。但如果您已经有一个项目项,您可以使用ProjectItem接口(http://msdn.microsoft.com/en-us/library/envdte.projectitem.aspx)来操作它。 - jb_
我显然很迟钝,但如果我正在指定汇编和要反射的类型..我看不出好处。我需要在模型内迭代汇编吗? - nologo
我正在嗅探 <CodeClass>。 - nologo

0
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>();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接