C# 通过对同一程序集的反射生成代码

C# 通过对同一程序集的反射生成代码,c#,.net,reflection,t4,C#,.net,Reflection,T4,我已经开始涉足T4,一开始相处得很好,但后来遇到了一个事实上很明显而且可能无法解决的问题,但也许有一种方式我只是缺乏了解或了解的经验 鉴于以下类别: 公共类测试:CodeActivity { 受保护的覆盖无效执行(CodeActivityContext上下文) { } [输入(“InX”)] 公共InArgument InX{get;set;} [输出(“输出”)] 公共输出参数OutX{get;set;} } 我希望将此作为输出: 公共类活动包装器 { 私有只读T4Test_活动; 私有只读

我已经开始涉足T4,一开始相处得很好,但后来遇到了一个事实上很明显而且可能无法解决的问题,但也许有一种方式我只是缺乏了解或了解的经验

鉴于以下类别:

公共类测试:CodeActivity
{
受保护的覆盖无效执行(CodeActivityContext上下文)
{
}
[输入(“InX”)]
公共InArgument InX{get;set;}
[输出(“输出”)]
公共输出参数OutX{get;set;}
}
我希望将此作为输出:

公共类活动包装器
{
私有只读T4Test_活动;
私有只读ActivityContext\u上下文;
公共ActivityWrapper(测试活动,ActivityContext上下文)
{
这个。_活动=活动;
这._context=context;
}
公共字符串InX
{
get{返回this._activity.InX.get(this._context);}
}
公共字符串输出
{
get{返回this._activity.OutX.get(this._context);}
set{this._activity.OutX.set(this._context,value);}
}
}
我已经找到了我需要的反射内容,我知道T4代码应该是什么样子,但有一个问题:我需要它与
T4Test
类在同一个项目中。然而,要加载程序集并对其进行反思,需要对其进行编译——但如果我打算修改同一程序集的代码,这当然有点困难。(我猜NCrunch不会简化事情。)

下面是我希望仍能解决这一问题的方法:

  • 项目将在没有生成类的情况下编译。这是因为该类将实现由IoC容器自动注册/解析的接口。它也是不可测试的,因为
    ActivityContext
    不能被模拟
  • 出于这个原因,它不必一直存在或正确。在实际交付DLL之前,我只需要说“立即生成”
  • 出于同样的原因,我也不关心T4模板是否实际位于项目中——只要生成的文件最终位于项目中(尽管不需要模板的另一个项目,也不需要构建后期构建事件来复制
    .cs
    文件)
  • 准确地说,它甚至不需要是T4。如果有其他可行的方法,我也很乐意使用
有没有办法做到这一点?(这是否足够清楚?

T4Test.tt


活动.tt


我想提出一种反映生成的组件的替代方案,因为只有当项目成功构建并在组件未过时的情况下生成适当的输出时,转换T4才有效

如果使用特定于主机的T4模板,则可以通过EnvDTE接口访问Visual Studio自动化模型。使用它,您可以遍历当前加载的VisualStudio解决方案的代码模型,而无需首先构建它

看看我对这个问题的回答:。借助有形模板库中的免费模板,您可以在设计时轻松“反映”现有类,并检测用所需属性修饰的属性:

<#
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)
{
    // iterate all properties
    var allProperties = VisualStudioHelper.GetAllCodeElementsOfType(codeClass.Members, EnvDTE.vsCMElement.vsCMElementProperty, true);
    foreach(EnvDTE.CodeProperty property in allProperties)
    {
        // check if it is decorated with an "Input"-Attribute
        if (property.Attributes.OfType<EnvDTE.CodeAttribute>().Any(a => a.FullName == "Input"))
        {
            ...
        }
    }
}
#>
a.FullName==“输入”))
{
...
}
}
}
#>

您是否考虑过在T4模板中生成整个类?也就是说,定义几个helper方法来创建一个小的DSL,然后列出要在模板中生成的类成员?您的意思是以不同的形式(XML或其他)定义属性,然后从模板生成两个类?考虑到我正在处理的有限变化,这可能真的有效。“助手方法”的背后是什么;这些将用于什么?是的,从模板生成两个类。我将发布一个示例来说明helper方法。更复杂的答案是使用roslyn解析C#语法树,但老实说@dtb建议更好。谢谢;明天我得把这个看得更好。我现在似乎理解的是,在日常使用中,这将是一个
.tt
文件,当我将其放入项目中时,它缺少第二个代码块(
var t4test
等),我只需要添加该声明就可以完成它,对吗?这实际上可能比仅仅生成包装器类节省更多的工作,因为活动类本身几乎已经是所有的样板。您甚至可以将模板拆分为两个文件。我已经相应地更新了示例。谢谢;这似乎是最灵活、最有效的选择——但我实际上如何生成代码呢?如何从
GenerateCode()
写入输出文件?似乎无法从嵌套类生成代码;我已经相应地更新了示例;
WriteLine
就是我要找的东西。我认为应该这样做,但不知道方法名。现在东西开始就位了。:-)非常感谢。这正是我最初寻找的东西,尽管很明显,考虑到我这一代人的输入性质,我没有寻找正确的东西。