【问题标题】:C# How to generate code from codeC#如何从代码生成代码
【发布时间】:2010-05-03 03:18:25
【问题描述】:

是否可以基于同一个项目的代码生成和构建一些 c# 代码。我尝试使用 T4 和 Reflection,但存在一些装配锁定问题。有没有其他办法?

【问题讨论】:

  • 我能问一下是什么让你离开了内省引擎吗? olegsych.com/2007/12/…
  • Microsoft.Cci.dll 和 FxCop 许可证存在一些问题。不允许单独使用。另外,我对T4引擎很熟悉。
  • 从 VS 2010 SP1 开始,在使用来自 T4 的反射时应该有 no locking issues

标签: c# code-generation


【解决方案1】:

反射对我来说很好用。您可以通过将构建任务隔离到 VS 中的单独 AppDomain 来解决程序集锁定问题。任务完成后,您需要用于代码生成的任何程序集都将与任务的 AppDomain 一起卸载。见AppDomainIsolatedTask

【讨论】:

  • 不知道我是否理解。我应该编写自己的构建任务,它继承 AppDomaniIsolatedTask 并启动 T4 代码生成器。是这样吗?
  • 是的,这样您应该能够解决 VS 在构建期间锁定程序集的问题。至于实际的代码生成器,请使用最适合您的 - 如果您喜欢 T4,请使用 T4。
【解决方案2】:

您绝对可以使用 C# 编写自己的代码生成器 - 毕竟,正在生成的“代码”只是您写出的文本文件。

但是 T4 模板有什么问题?它们提供了许多功能,您不必再次重新发明 - 为什么不使用它呢?您能否更详细地告诉我们您在使用 T4 时遇到了什么问题?

T4 实际上也只是 .NET 中的一堆类 - 所以您绝对可以编写自己的代码生成器来处理一些逻辑,并使用 T4 来进行模板化和替换这些模板值部分。但同样:为了帮助您诊断您的 T4 问题,我们需要了解更多关于这些的信息......

【讨论】:

  • 例如,我想为我的 L2S 模型生成一个 CloneEntity。我需要读取属性并生成克隆方法。可以使用 T4 和反射来完成,但存在关于程序集锁定的问题。每次运行后,您必须关闭 VS 并再次打开它。
  • 至于 CloneEntity:为什么不将实体序列化为内存流并从那里反序列化呢?这是做这件事的标准方式,它已经证明了它的价值,它不需要任何诡计或代码生成......
【解决方案3】:

This example from Oleg Sych 使用 FXCop 的自省引擎而不是反射。这样,程序集就不会被锁定。

很遗憾,Reflection 已优化 用于代码执行。一个特别的 限制使它不适合 代码生成 - 加载的程序集 使用反射只能卸载 使用它的 AppDomain。因为T4 模板被编译成 .NET 程序集和缓存以改进 代码生成的性能,使用 反射访问组件 装配会导致 T4 将其锁定。

或者,如果您只针对 Linq to SQL 类,您可以从 dbml 文件生成代码,而不是 L2S 从 dbml 生成的代码。 I've got an example of something similar (an edmx file) on my own blog.

【讨论】:

    【解决方案4】:

    我们在工作中使用 JavaCC 的第三方 C# .NET 变体。

    还有一篇关于如何制作的有趣文章: http://msdn.microsoft.com/en-us/magazine/cc136756.aspx

    【讨论】:

      【解决方案5】:

      这真的取决于你到底想达到什么目标,但在一般情况下,我建议使用 T4 模板。

      是的,可以在您的项目中使用 T4 模板根据一些本地设置在您的项目中生成代码,但您应该定义您要执行的操作。

      如果你想根据你在同一个项目中定义的一些类生成代码——这听起来并不容易实现(毕竟你想编译当前项目中的一些类,生成一些基于在他们身上,然后再次生成类......嗯......?)

      但如果您想存储一些设置,然后运行 ​​T4 模板并根据这些设置生成一些代码 - 这很容易实现。 T4MVC 就是一个示例(它们基于设置文件生成代码,该设置文件与 T4 模板一起复制并存储在项目中)。此模板还查看解决方案中可用的当前文件,并根据每个文件生成字符串常量。那种听起来真的会帮助你解决你的问题,不管它是什么:)

      如果您仍然不确定 - 您可以详细说明您想要做什么,我们会尽力帮助您:)

      【讨论】:

      • 感谢您的回答。我想要实现的是能够基于我的项目中的类生成额外的代码。像 CloneEntity()、SerializeEntity() 或 InvokeSomeMethod 之类的东西。所有这些代码都依赖于类名、成员...生成的代码可以在另一个项目中,但将所有内容放在一起会更好。
      • 我明白了.. 您很可能不得不将这些类保存在一个单独的项目中,因为您正在尝试在半生成的实体上生成代码,我不确定这是否可能.听起来如果您遵循与您使用的完全相同的方法,但将这些 T4 保存在单独的组件中 - 它应该可以正常工作(当然,它不必是一个单独的组件,只有 T4 ......您可以拥有任何其他里面有各种各样的东西,但是 T4 应该在一个单独的、已经编译的程序集中反映类:) ) 祝你好运!
      猜你喜欢
      • 2012-03-04
      • 1970-01-01
      • 2015-10-25
      • 2017-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-31
      • 1970-01-01
      相关资源
      最近更新 更多