C#预处理器

时间:2020-03-05 18:45:46  来源:igfitidea点击:

尽管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可以为我们做什么?