当前位置:  开发笔记 > 编程语言 > 正文

预处理器中的C#宏定义

如何解决《预处理器中的C#宏定义》经验,为你挑选了5个好方法。

C#能否像使用预处理器语句在C编程语言中那样定义宏?我想简化某些重复语句的常规输入,如下所示:

Console.WriteLine("foo");

Andrew Hare.. 48

不,C#不支持像C这样的预处理器宏.另一方面,Visual Studio有片段.Visual Studio的代码片段是IDE的一个功能,在编辑器中进行了扩展,而不是在预处理器的编译代码中替换.



1> Andrew Hare..:

不,C#不支持像C这样的预处理器宏.另一方面,Visual Studio有片段.Visual Studio的代码片段是IDE的一个功能,在编辑器中进行了扩展,而不是在预处理器的编译代码中替换.


当相同的代码库必须针对多个编译时目标(如iOS,Android,MacOSX等)时,@ weberc2宏非常有用.缺少宏意味着你必须在`#if/#asseif之间放置大量代码/#else`pragma当使用一些简单的宏时,可以以高效/优雅和可维护的方式为每个目标发出正确的代码.简而言之,当您必须包含无法在某些目标上编译的代码时,C风格的宏非常有用.
@ weberc2糟糕的程序员不应该破坏我们其他人的优雅功能
@Jake Macros不是"优雅的功能",它们是对糟糕的语言设计的补偿.
@ weberc2这个"更好的解决方案"的问题在于它很重,并且可以在多个文件上传播一些简单的代码行,这些代码必须全部被理解才能理解完整的解决方案.我不同意这更好.是的,C预处理器被滥用到折磨点(我绝对是滥用者!),但在许多情况下它也非常有用,使代码更简单,更容易理解.
@ weberc2我们谈论的是两件不同的事情.我不是说围绕大块代码的一堆`#ifdefs`是好的.不是.我说司法使用`#ifdef PLATFORM1 #elif PLATFORM2 ......中嵌入的`#define MACRO(x,y)`在有限的情况下可以作为工具箱中的工具使用.也许你不同意这一点 - 在谷歌搜索保护预处理器后似乎世界上大多数人也这样做了.但我确实遇到了[这个宝石.](http://stackoverflow.com/a/653028/9648)
@JohnnyLambada如果您真的想在尽量减少痛苦的情况下使用预处理器,请不要使用您的平台逻辑定义宏,否则您将不得不在整个代码库中处理调试/读取宏.相反,在尽可能少的文件中,定义封装预处理器逻辑的函数,这样您就不必在其他任何地方担心它.但是,使用构建系统有条件地编译文件而不是预处理器仍然会更好.
@Jake这不是因为你从来没有遇到过这样的情况,即绝对不需要这种情况.这实际上是什么让我来到这里,让我告诉你你的评论是多么无用......
对于那些假装宏是坏的:C#项目使用大量的"宏",它们只是以在编译器外部运行的代码生成器的形式出现.但是,外部代码生成器使构建复杂化并创建更多非标准DSL.我宁愿有能力编写编译器宏来发出重复的代码块,而不是编写外部代码生成器.宏也可以做很多事情,函数不能.(提取__line__,生成样板)说,我更喜欢我的宏是语法宏,更像是Nemerle或Boo,而不是C预处理器.
@ Virus721它可能看起来没用了.我最初回复了几年前[weberc2](http://stackoverflow.com/users/483347/weberc2)发表的评论,他从此删除了它.他最初的评论是,"感谢上帝没有宏. - weberc2 12月25日12:27"

2> 小智..:

您可以使用C预处理器(如mcpp)并将其装入.csproj文件中.然后,您可以在源文件中编译"构建操作",从"编译"到"预处理"或您调用的任何内容.只需将BeforBuild添加到您的.csproj中,如下所示:

  


  

您可能必须在至少一个文件(在文本编辑器中)手动更改编译到预处理 - 然后在Visual Studio中可以选择"预处理"选项.

我知道宏被严重过度使用和误用,但是如果不是更糟的话,将它们完全删除也同样糟糕.宏使用的典型示例是NotifyPropertyChanged.每个必须手动重写这段代码的程序员都知道没有宏会有多痛苦.


您必须获得一些"创新"解决方案,以及开箱即用的思考.但对于阅读这个"解决方案"的人来说,只是一句忠告,请不要这样做.有些东西只是*错误*,就是这样的黑客攻击.这是其中之一.
@danpalmer为什么在'MyCommon.targets`中添加CPP shellout只是*错*?CPP可以做的一些事情使语言难以置信.IMO,更糟糕的是开发人员在编写`throw new ArgumentNullException("argumentName");`时必须实际手动字符串化参数名称.代码契约本来应该解决这个问题,但它需要一个IL重写器使用`.targets`进行操作,对于CPP调用来说应该不会更糟.

3> anthonybell..:

我用它来避免Console.WriteLine(...):

public static void Cout(this string str, params object[] args) { 
    Console.WriteLine(str, args);
}

然后你可以使用以下内容:

"line 1".Cout();
"This {0} is an {1}".Cout("sentence", "example");

它简洁而有点时髦.


如果使用制表符完成则不久.您正在创建两种完全相同的方法,这会让其他开发人员感到困惑.而且,它并不优雅; 你可能会在Python中看到这种东西,但它在C#中很奇怪.
这不是预处理器宏.这个问题的解决方案明确指出:"C#不支持像c这样的预处理器宏"
+1用于制作扩展方法.虽然...因为C#不是C++,我个人可能会称它为.ToConsole()而不是Cout().当然,"Cout"中的"C"表示控制台,而.ToConsole()更长,但.ToConsole()也是一种更常见的通用.NET模式,对于不是来自C++背景的人来说可能更有意义,*并且*Intellisense将接收它并让你只需键入.ToC并点击空格键即可完成它.
-1:这不仅是一个非常具体的用例,通常不能轻易应用,但它甚至也不是预处理器宏的保证.
因此,您不必键入`Console.WriteLine(...)`(这需要经常输入很长时间).你可以编写自己的方法来做到这一点,但使用字符串扩展是一个更优雅的恕我直言.

4> sraboy..:

虽然你不能编写宏,但在简化你的例子之类的东西时,C#6.0现在提供了静态用法.以下是Martin Pernica在他的Medium文章中给出的例子:

using static System.Console; // Note the static keyword

namespace CoolCSharp6Features
{
  public class Program
  {
    public static int Main(string[] args)
    {
      WriteLine("Hellow World without Console class name prefix!");

      return 0;
    }
  }
}



5> Binkan Salar..:

没有直接等价于C风格的宏在C#中,但inlined静态方法-用或不用#if/ #elseif/ #else编译指示-是你可以得到的最接近:

        /// 
        /// Prints a message when in debug mode
        /// 
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static unsafe void Log(object message) {
#if DEBUG
            Console.WriteLine(message);
#endif
        }

        /// 
        /// Prints a formatted message when in debug mode
        /// 
        /// A composite format string
        /// An array of objects to write using format
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static unsafe void Log(string format, params object[] args) {
#if DEBUG
            Console.WriteLine(format, args);
#endif
        }

        /// 
        /// Computes the square of a number
        /// 
        /// The value
        /// x * x
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static double Square(double x) {
            return x * x;
        }

        /// 
        /// Wipes a region of memory
        /// 
        /// The buffer
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static unsafe void ClearBuffer(ref byte[] buffer) {
            ClearBuffer(ref buffer, 0, buffer.Length);
        }

        /// 
        /// Wipes a region of memory
        /// 
        /// The buffer
        /// Start index
        /// Number of bytes to clear
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static unsafe void ClearBuffer(ref byte[] buffer, int offset, int length) {
            fixed(byte* ptrBuffer = &buffer[offset]) {
                for(int i = 0; i < length; ++i) {
                    *(ptrBuffer + i) = 0;
                }
            }
        }

这可以完美地用作宏,但有一个缺点:标记为inlined的方法将像其他“常规”方法一样复制到程序集的反射部分。

推荐阅读
乐韵答题
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有