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

标签 c# .net 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; }
}

我想要这个作为输出:

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); }
    }
}

我已经弄清楚了我需要的反射内容,并且我知道 T4 代码应该是什么样子,但是有一个问题:我需要在与 T4Test 类相同的项目中使用它。但是,要加载程序集并对其进行反射,需要对其进行编译——当然,如果我打算修改同一个程序集的代码,这就有点困难了。 (我想 NCrunch 并没有简化事情。)

下面是我希望仍然可以解决这个问题的事情:

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

有什么办法可以实现吗? (这还不够清楚吗?)

最佳答案

我想提出一个反射(reflect)生成的程序集的替代方案,因为只有当项目成功构建并生成正确的输出时转换 T4 才有效,前提是程序集没有过时。

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

看看我对这个 SO 问题的回答:Design Time Reflection .借助 tangible 的模板库中的免费模板,您可以在设计时轻松地“反射(reflect)”您现有的类,并检测使用所需属性装饰的属性:

<#
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"))
        {
            ...
        }
    }
}
#>

关于c# - 通过对同一程序集的反射生成代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15626157/

相关文章:

c# - C# 中的任务并行库和 PLINQ 替代方案

c# - 将新的 XElement 添加到 Xdocument

c# - 异常处理的良好实践设计模式

java - 使用反射重置枚举单例字段

c# - 如何使用反射调用泛型方法?

c# - 如何在用户 session 被锁定时注销用户

c# - C# List<char[]> 是否分配在连续内存中?

c# - 使用外部事件打破 while 循环

c# - ServiceStack 请求 DTO 设计

java - 如何检查类是否已使用 Kotlin 或 Java 中的反射覆盖接口(interface)中的默认方法?