代码生成器或T4模板,它们真的很邪恶吗?我听说有人说不应该使用代码生成器和T4模板。这背后的逻辑是,如果你使用生成器来生成你的代码,那么有一种更好、更有效的方法来通过泛型和模板来构建它。虽然我有点同意上面的说法,但我还没有真正找到一种有效的方法来构建模板,例如实例化自己可以这么说。换句话说,我永远做不到:returnnewT();此外,如果我想根据数据库值生成代码,我发现使用带有T4模板的Microsoft.SqlServer.Management.SMO可以很好地生成大量代码,而不需要复制/粘贴或使用resharper。我在泛型中发现的许多问题让我感到震惊,因为有那么多开发人员不理解它们。当我检查泛型的解决方案时,有时它会变得复杂,因为C#说你不能做在我看来合乎逻辑的事情。你怎么看?你喜欢构建生成器,还是更喜欢使用泛型?另外,仿制药能走多远?我对泛型了解很多,但我不断遇到导致我使用T4模板的陷阱和误区。处理需要大量灵活性的场景的更合适方法是什么?哦,作为这个问题的奖励,C#和泛型有哪些好的资源?你可以做newT();如果你做publicclassMehwhereT:new(){publicstaticTCreateOne(){returnnewT();}}至于代码生成器。我每天都用一个,没有任何问题。我现在正在使用一个:-)泛型解决一个问题,代码生成器解决另一个问题。例如,使用UML编辑器创建业务模型,然后使用该工具生成带有持久化代码的类,不能使用泛型来实现,因为每个持久化类都是完全不同的。至于仿制药的良好来源。最好的当然是JonSkeet的书!?作为T4的创始人,我不得不多次为这个问题辩护,正如您想象的那样:-)我的信念是,最好的代码生成是朝着使用可重用库生成同等价值迈出的一步。正如许多其他人所说,维护DRY的关键概念绝不是手动更改生成的代码,而是在源元数据更改或您在代码生成器中发现错误时保留重新生成的能力。此时生成的代码具有目标代码的许多特征,并且不会出现复制/粘贴类型的问题。一般来说,制作一个参数化代码生成器(尤其是基于模板的系统)比正确设计一个将使用成本降低到相同水平的高质量基础库要少得多,所以这是一种快速获得.价值来自一致性并消除重复性错误。但是,我仍然相信完成的系统通常会通过减少总代码量来改进。如果没有别的,它几乎总是有一个小得多的内存占用(虽然人们倾向于认为泛型在这方面是免费的,但他们当然不是)。如果您使用代码生成器实现了一些价值,那么通常会花费您一些时间或金钱或善意来投资从生成的代码库中获取库。然后您可以逐步重新设计代码生成器以针对新库并希望生成更少的代码。冲洗并重复。我已经提到并出现在这篇文章中的一个有趣的反驳点是,就学习曲线而言,丰富、复杂的参数库并不是最简单的,尤其是对于那些没有深入了解该平台的人来说。将代码生成放在更简单的基础框架上可能会导致代码冗长,但它通常非常简单且可读性强。当然,如果你的生成器有很多变化和极其丰富的参数化,你可能只是为了模板的复杂性而牺牲复杂性。这是一条容易进入的道路,维护起来可能会变得非常头疼-请注意这一点。生成的代码并不邪恶,它没有气味!关键是在正确的时间生成正确的代码。我认为T4很棒-我只是偶尔使用它,但当我使用时它非常有用。无条件地,生成的代码无条件地疯狂!如果没有代码生成,VisualStudio2010的很大一部分将无法实现。实体框架是不可能的。将控件拖放到窗体上这样简单的事情是不可能的,Linq也不可能。说不应该使用代码生成是很奇怪的,因为许多人甚至都没有考虑过就使用了它。在我看来,代码生成器很好,只要代码生成是正常构建过程的一部分,而不是运行一次然后保留其输出的东西。我添加此警告是因为如果您只使用一次代码生成器并丢弃创建它的数据,那么您只是自动创建一个大规模的DRY违规和维护问题;而每次生成代码实际上意味着无论你用什么构建都是真正的源代码,生成的文件只是你应该忽略的中间编译阶段。Lex和yacc是经典的工具示例,它们允许您以高效的方式指定函数并从中生成高效的代码。尝试手动做事会增加您的开发时间,并可能导致代码效率低下和可读性差。虽然您当然可以将lex和yacc之类的东西直接合并到您的代码中,并在运行时而不是编译时完成它们的工作,但这肯定会给代码增加相当大的复杂性并降低速度。如果您确实需要在运行时更改规范,这可能是值得的,但在大多数正常情况下,使用lex/yacc在编译时为您生成代码是一个巨大的胜利。也许这有点苛刻,但代码生成对我来说有味道。使用该代码生成意味着有许多潜在的共同原则可以用“不要重复自己”的方式表达。这可能需要更长的时间,但是当您基于包含机制的基础设施最终只得到包含真正改变的位的类时,它是令人满意的。对于泛型……不,我没有太多问题。目前唯一不起作用的是说Lista=newList();清单o=a;但即便如此,下一个版本的C#也会如此。更多的代码意味着更多的复杂性。更多的复杂性意味着更多的错误可以隐藏的地方,这意味着更长的修复周期,这反过来又意味着总体上成本更高的项目。只要有可能,我宁愿尽量减少代码量来提供相同的功能;理想情况下使用动态(编程)方法而不是代码生成。反思、属性、方面和类属为干旱战略提供了许多选择,发电是最后的手段。对我来说,代码生成是解决在语言、框架等中发现的许多问题的方法。它们本身并不是邪恶的,我想说发布一种语言(C#)是非常非常糟糕的(即邪恶的)并迫使你去复制和粘贴(交换属性、事件触发、缺少宏)或使用幻数(wpf绑定)。所以,我哭了,但我不得不使用它们。我使用过T4代码生成和泛型。两者都不错,各有利弊,适合不同的用途。就我而言,我使用T4基于数据库模式生成实体、DAL和BLL。但是,DAL和BLL指的是我基于泛型和反射构建的迷你ORM。所以我认为你可以并排使用它们,只要你能控制它并保持小而简单。T4生成静态代码,而泛型是动态的。如果使用泛型,就会使用反射,据说反射比“硬编码”解决方案效率低。当然,你可以缓存反射结果。关于“returnnewT();”,我使用这样的动态方法:publicclassObjectCreateMethod{delegateobjectMethodInvoker();方法调用者methodHandler=null;publicObjectCreateMethod(Type类型){CreateMethod(type.GetConstructor(Type.EmptyTypes));}publicObjectCreateMethod(ConstructorInfotarget){CreateMethod(target);}voidCreateMethod(ConstructorInfotarget){DynamicMethoddynamic=newDynamicMethod(string.Empty,typeof(object),newType[0],target.DeclaringType);ILGeneratoril=dynamic.GetILGenerator();il.DeclareLocal(target.DeclaringType);il.Emit(OpCodes.Newobj,target);il.Emit(OpCodes.Stloc_0);il.Emit(OpCodes.Ldloc_0);il.Emit(OpCodes.Ret);methodHandler=(MethodInvoker)dynamic.CreateDelegate(typeof(MethodInvoker));}publicobjectCreateInstance(){returnmethodHandler();}}然后,我这样称呼它:ObjectCreateMethod_MetodoDinamico=newObjectCreateMethod(info.PropertyType);对象_nuevaEntidad=_MetodoDinamico.CreateInstance();泛型和代码生成是两件事。在某些情况下,您可以使用泛型而不是代码生成,我认为您应该这样做。对于其他情况,代码生成是一个强大的工具。对于您只需要根据一些数据输入生成代码的所有情况,代码生成是必经之路。最明显但绝不是唯一的例子是VisualStudio中的表单编辑器。这里的输入是设计器数据,输出是代码。在这种情况下,泛型并没有真正的帮助,但VS只根据GUI布局生成代码就完全没问题了。代码生成器可以被认为是代码味道,表明目标语言中存在错误或功能缺失。例如,虽然这里曾经说过“持久化对象不能被泛化”,但最好将其理解为“C#中自动保存其数据的对象不能在C#中被泛化”,因为我当然可以通过使用各种方法在Python中执行此操作。然而,Python方法可以通过使用operator[](method_nameasstring)在静态语言中进行模拟,它可以根据需要返回一个仿函数或一个字符串。不幸的是,这个解决方案并不总是适用,返回一个仿函数可能不方便。我想说的是,代码生成器通过为手头的特定问题提供更方便的专用语法来指示所选语言中的缺陷。生成代码的复制/粘贴类型(如ORMsmake)也非常有用……您可以创建数据库,然后让ORM用您喜欢的语言生成数据库定义的副本。当您更改原始定义(数据库)时,优势就来了,按编译和ORM(如果您有一个好的)可以重新生成定义的副本。所有对数据库的引用现在都由编译器类型检查器检查,当您使用不再存在的表或列时,您的代码将不会编译。想一想:如果我在代码中多次调用一个方法,那不就是我最初给方法起的名字吗?我一遍又一遍地重复这个名字……语言设计者认识到了这个问题并提出了“类型安全”作为解决方案。不是删除副本(正如DRY建议的那样),而是检查它们的正确性。ORM生成的代码在引用表名和列名时带来了相同的解决方案。不要删除副本/引用,而是将数据库定义引入您的(类型安全)语言,您可以在其中引用类和属性。与编译器类型检查一起,这以类似的方式解决了类似的问题:当您引用过时或拼写错误的表(类)或列(属性)时,它保证是编译时错误而不是运行时错误。Quote:我还没有真正找到一种有效的方法来构建模板,例如实例化自己可以这么说。换句话说,我永远做不到:returnnewT();publicabstractclassMehBase其中TSelf:MehBase,new(){publicstaticTSelfCreateOne(){returnnewTSelf();}}publicclassMeh:MehBase,TParam1,TParam2>{publicvoidProof(){MehinstanceOfSelf1=Meh.CreateOne();MehinstanceOfSelf2=Meh.CreateOne();代码生成,如泛型、模板和其他类似的快捷方式,是一个强大的工具。像大多数强大的工具一样,它放大了用户的善与恶——他们无法分开。因此,如果您彻底了解您的代码生成器,预测它将生成的所有内容以及原因,并出于正当理由打算这样做,那么您会没事的。但不要使用它(或任何其他技术)将您带到您不确定要去哪里或如何到达那里的地方。有些人认为,如果你解决了当前的问题并实施了一些行为,那么你就是黄金。对于下一个开发人员(也许是您自己)来说,您在路径中留下了多少瑕疵和不透明并不总是很明显。为什么能够非常、非常快地复制/粘贴,使其更容易被接受?这是我能看到代码生成的唯一原因。即使生成器提供了您需要的所有灵活性,您仍然必须学习如何使用这种灵活性——这是所需的另一层学习和测试。即使它以零时间运行,它仍然会使代码膨胀。我推出了自己的数据访问类。它知道关于连接、事务、存储过程参数等的一切。我只需要编写一次所有的ADO.NET东西。自从我必须编写(甚至查看)任何带有连接对象的东西以来已经有很长一段时间了,而且我很难记住手写的语法。C#学习教程到此为止:代码生成器或T4模板,它们真的很邪恶吗?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
