C#预处理器
尽管Cspec确实包含预处理程序和基本指令(#define,#if等),但是该语言没有像C / C ++这样的语言中所具有的灵活的预处理程序。我相信缺少如此灵活的预处理器是Anders Hejlsberg的设计决定(尽管很遗憾,我现在找不到对此的参考)。从经验来看,这无疑是一个不错的决定,因为当我执行大量C / C ++时,会创建一些非常糟糕的不可维护的宏。
也就是说,在许多情况下,我可以找到稍微灵活一些的预处理器有用。可以通过一些简单的预处理程序指令来改进如下代码:
public string MyProperty { get { return _myProperty; } set { if (value != _myProperty) { _myProperty = value; NotifyPropertyChanged("MyProperty"); // This line above could be improved by replacing the literal string with // a pre-processor directive like "#Property", which could be translated // to the string value "MyProperty" This new notify call would be as follows: // NotifyPropertyChanged(#Property); } } }
编写一个预处理器来处理这种极其简单的情况是一个好主意吗?史蒂夫·麦康奈尔(Steve McConnell)在《代码完成》(p208)中写道:
Write your own preprocessor If a language doesn't include a preprocessor, it's fairly easy to write one...
我被撕裂了。将这样的灵活预处理器排除在C#之外是一项设计决策。但是,我高度尊重的一位作者提到在某些情况下可能还可以。
我应该建立一个Cpre处理器吗?有没有一种可以做我想做的简单事情?
解决方案
回答
Should I build a C# pre-processor? Is there one available that does the simple things I want to do?
我们始终可以使用C预处理器-C在语法上足够接近。也可以选择M4.
回答
考虑看一下诸如PostSharp之类的面向方面的解决方案,该解决方案基于事实基于自定义属性注入代码。它与预编译器相反,但是可以为我们提供所需的功能(PropertyChanged通知等)。
回答
如果要设计C#的下一版本,我会考虑每个函数都有一个自动包含的局部变量,该局部变量包含类的名称和函数的名称。在大多数情况下,编译器的优化器会将其删除。
我不确定这种事情有很多需求。
回答
我知道很多人认为短代码等于优雅代码,但事实并非如此。
如我们所展示的,我们提出的示例已通过代码完美地解决了,我们需要预处理器指令做什么?我们不想"预处理"代码,而是希望编译器在属性中为我们插入一些代码。这是通用代码,但这不是预处理器的目的。
以示例为例,我们将限制放在哪里?显然,这满足了观察者模式,并且毫无疑问将是有用的,但是实际上有很多事情会有用,因为代码提供了灵活性,而预处理器则没有。如果我们尝试通过预处理程序指令实现通用模式,则将以需要与语言本身一样强大的预处理程序结尾。如果要以不同的方式处理代码,请使用预处理器指令,但是如果我们只想要代码片段,则可以找到另一种方式,因为预处理器不是要这样做。
回答
@Jorge wrote: If you want to process your code in a different way the use a preprocessor directive but if you just want a code snippet then find another way because the preprocessor wasn't meant to do that.
有趣的。我并不真正认为预处理器一定会以这种方式工作。在提供的示例中,我正在做一个简单的文本替换,这与Wikipedia上预处理器的定义一致。
如果这不是预处理器的正确使用,那么我们应该怎么称呼简单的文本替换,通常需要在编译之前进行?
回答
主要论点反对在Visual Studio中构建Cis集成的前处理程序:要花很多精力(如果可能的话)来获得智能感知和新的背景编译才能无缝地工作。
替代方法是使用Visual Studio生产力插件,例如ReSharper或者CodeRush。
就我所知,后者拥有无与伦比的模板系统,并带有出色的重构工具。
可以解决所指问题的确切类型的另一件事是诸如PostSharp之类的AOP框架。
然后,我们可以使用自定义属性来添加通用功能。
回答
要获取当前执行的方法的名称,可以查看堆栈跟踪:
public static string GetNameOfCurrentMethod() { // Skip 1 frame (this method call) var trace = new System.Diagnostics.StackTrace( 1 ); var frame = trace.GetFrame( 0 ); return frame.GetMethod().Name; }
当我们使用属性设置方法时,名称为set_Property。
使用相同的技术,我们还可以查询源文件和行/列信息。
但是,我没有对此进行基准测试,为每个属性集创建一次stacktrace对象可能会非常耗时。
回答
我认为在实现INotifyPropertyChanged时,我们可能会丢失问题的重要部分。消费者需要一种确定属性名称的方法。因此,我们应该将属性名称定义为常量或者静态只读字符串,这样,使用者就不必"猜测"属性名称。如果使用预处理器,那么消费者将如何知道该属性的字符串名称是什么?
public static string MyPropertyPropertyName public string MyProperty { get { return _myProperty; } set { if (!String.Equals(value, _myProperty)) { _myProperty = value; NotifyPropertyChanged(MyPropertyPropertyName); } } } // in the consumer. private void MyPropertyChangedHandler(object sender, PropertyChangedEventArgs args) { switch (e.PropertyName) { case MyClass.MyPropertyPropertyName: // Handle property change. break; } }
回答
如果我们准备放弃C,则可能想看看Boo语言,该语言通过AST(抽象语法树)操作具有非常灵活的宏支持。如果我们可以放弃Clanguage,的确是很棒的东西。
有关Boo的更多信息,请参见以下相关问题:
- 非C ++语言的生成式编程?
- https://stackoverflow.com/questions/595593/who-is-using-boo-programming-language
- Boo与IronPython
- NET的良好动态编程语言推荐
- Boo可以为我们做什么?