Genuilder.Extensibility框架:自定义代码生成指南

在软件开发过程中,代码生成是一个常见的需求,它可以帮助自动化重复性的工作,提高开发效率。Genuilder.Extensibility框架提供了一种简单而强大的方法来实现这一目标。本文将详细介绍如何在Visual Studio项目中使用Genuilder.Extensibility来生成自定义代码。

简介

如果之前使用过项目Genuilder,那么可能已经熟悉了它的强大功能。Genuilder是一个Visual Studio扩展,它使用MSBuild来执行各种任务,如配置文件检查等,而无需任何安装。Genuilder.Extensibility是Genuilder的一个新特性,它允许在编译过程中轻松生成自己的代码。不需要了解MSBuild,不需要修改项目文件,也不需要成为C#专家。只需要知道如何在Visual Studio中引用一个程序集并创建一个新的类库。

如何在项目中使用Genuilder

要在项目中使用Genuilder,首先需要阅读官方文档。这里简要说明一下步骤:创建一个控制台应用程序,并使用将要创建的InterfaceExtractor特性。将Genuilder的bin文件夹复制到解决方案文件夹中。然后使用Genuilder的GUI,浏览到解决方案并激活项目中的Genuilder。这样就完成了!

如何创建自己的特性

要创建自己的特性,需要创建一个新的类库,项目名称必须遵循FEATURE_NAME.Gen的约定,这是强制性的。在特性项目中引用Genuilder和Genuilder.Extensibility,然后创建一个新的插件。插件是一个实现了IPlugin接口的类(例如HelloWorldPlugin)。接下来,将特性项目添加到项目引用中。在Initialize方法的实现中生成一个文件。

public class HelloWorldPlugin : IPlugin { public void Initialize(ICodeRepository repository) { var code = repository.Get("GeneratedCode.gen.cs"); code.Content = "class HelloWorld{}"; } }

编译后,将看到HelloWorld类,并且可以在IntelliSense中看到它。

如何创建源文件和生成源文件之间的依赖关系

如果源文件被删除,希望目标生成的代码自动从项目中删除,这可以通过使用CodeItem类的SourceOf和TargetOf方法来实现。这些方法返回一个CodeDependency对象,然后只需要注册到ShouldUpdateTarget事件即可。

public class DependencyHelloWorldPlugin : IPlugin { public void Initialize(ICodeRepository repository) { repository.CodeItemCreated += new CodeItemCreatedHandler(repository_CodeItemCreated); } void repository_CodeItemCreated(ICodeRepository sender, CodeItem item) { if (!item.Name.EndsWith("generated.cs")) { var dependency = item.SourceOf(item.Name + "generated.cs"); dependency.ShouldUpdateTarget += new CodeDependencyHandler(dependency_ShouldUpdateTarget); } } void dependency_ShouldUpdateTarget(CodeDependency sender, CodeItem target) { target.Content = String.Format("public class {0}{}", ToClassName(sender.Source.Name)); } private string ToClassName(string fileName) { return fileName.Replace('.', '_').Replace('/', '_').Replace('\\', '_'); } }

如何使用最喜欢的解析器解析和生成代码

可以使用NRefactory(SharpDevelop的解析器)与Genuilder集成。Genuilder.Extensibility附带了一个扩展,它将NRefactory与Genuilder集成在一起。扩展是一个以CodeItem为构造函数参数的类。在特性项目中引用Genuilder.Extensibility.NRefactory、ICSharpCode.NRefactory和ICSharpCode.SharpDevelop.Dom。然后使用CodeItem.GetExtension<CompilationUnitExtension>()来使用扩展。

public class DependencyHelloWorldPlugin2 : IPlugin { public void Initialize(ICodeRepository repository) { repository.CodeItemCreated += new CodeItemCreatedHandler(repository_CodeItemCreated); } void repository_CodeItemCreated(ICodeRepository sender, CodeItem item) { if (!item.Name.EndsWith("generated2.cs") && HasAClassWithAttribute<GenerateAttribute>(item)) { var dependency = item.SourceOf(item.Name + "generated2.cs"); dependency.ShouldUpdateTarget += new CodeDependencyHandler(dependency_ShouldUpdateTarget); } } private bool HasAClassWithAttribute<T>(CodeItem item) { var nRefactoryExtension = item.GetExtension<CompilationUnitExtension>(); return HasAttribute<T>(nRefactoryExtension.CompilationUnit); } private bool HasAttribute<T>(INode node) { if (node is TypeDeclaration) { TypeDeclaration declaration = (TypeDeclaration)node; var hasAttribute = declaration.Attributes.SelectMany(attributes => attributes.Attributes).Any(attribute => attribute.Name.EndsWith(typeof(GenerateAttribute).Name)); if (hasAttribute) return true; } foreach (var child in node.Children) { var hasAttribute = HasAttribute<T>(child); if (hasAttribute) return true; } return false; } void dependency_ShouldUpdateTarget(CodeDependency sender, CodeItem target) { var nRefactoryExtension = target.GetExtension<CompilationUnitExtension>(); nRefactoryExtension.CompilationUnit.Children.Clear(); nRefactoryExtension.CompilationUnit.Children.Add(new TypeDeclaration(Modifiers.Public, new List<AttributeSection>()) { Name = ToClassName(sender.Source.Name) }); nRefactoryExtension.Save(); } private string ToClassName(string fileName) { return fileName.Replace('.', '_').Replace('/', '_').Replace('\\', '_') + "2"; } }

如何调试插件

打开特性项目的属性,然后转到调试选项卡。将启动程序设置为MSBuild(取决于.NET版本)。命令参数必须引用插件所在的项目。之后,当想要调试时,只需按F5即可。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485