通过反射在同一个程序集上生成代码

Tea*_*Dev 4 .net c# reflection t4

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

鉴于以下课程:

public class T4Test : CodeActivity
{
    protected override void Execute(CodeActivityContext context)
    {
    }

    [Input("InX")]
    public InArgument<string> InX { get; set; }

    [Output("OutX")]
    public OutArgument<string> OutX { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我希望这作为输出:

public class ActivityWrapper
{
    private readonly T4Test _activity;
    private readonly ActivityContext _context;

    public ActivityWrapper(T4Test activity, ActivityContext context)
    {
        this._activity = activity;
        this._context = context;
    }

    public string InX
    {
        get { return this._activity.InX.Get(this._context); }
    }

    public string OutX
    {
        get { return this._activity.OutX.Get(this._context); }
        set { this._activity.OutX.Set(this._context, value); }
    }
}
Run Code Online (Sandbox Code Playgroud)

我已经找到了我需要的反射内容,而且我知道T4代码应该是什么样子,但是有一个问题:我需要在与T4Test该类相同的项目中.但是,要加载程序集并反映它,需要编译它 - 但是如果我打算修改同一个程序集的代码,那当然有点困难.(我猜NCrunch不会简化事情.)

现在,我希望这些东西可以解决这个问题:

  • 项目将在没有生成的类的情况下编译.这是因为该类将实现由IoC容器自动注册/解析的接口.无论如何它也是不可测试的,因为ActivityContext不能被嘲笑.
  • 因此,它不必一直存在或纠正.我只需要能够在实际交付DLL之前说"立即生成".
  • 出于同样的原因,我也不关心T4模板是否实际位于项目中 - 只要生成的文件最终在项目中(尽管不需要模板的另一个项目并构建PostBuild事件来复制.cs文件) .
  • 确切地说,它甚至不需要是T4.如果有任何其他可行的方法,我也很乐意使用它.

有没有办法实现这个目标?(那是否足够清楚?)

Nic*_*ico 6

我想提出一种反映生成的程序集的替代方法,因为转换T4仅在项目成功构建时才有效,并且如果程序集未过时则生成正确的输出.

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

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

<#
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"))
        {
            ...
        }
    }
}
#>
Run Code Online (Sandbox Code Playgroud)