77

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

Console.WriteLine("foo");
4

10 回答 10

58

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

于 2009-04-02T12:14:04.460 回答
50

您可以使用 C 预处理器(如 mcpp)并将其安装到您的 .csproj 文件中。然后,您将源文件上的“构建操作”从 Compile 更改为 Preprocess 或您所称的任何内容。只需像这样将BeforBuild添加到您的 .csproj 中:

  <Target Name="BeforeBuild" Inputs="@(Preprocess)" Outputs="@(Preprocess->'%(Filename)_P.cs')">
<Exec Command="..\Bin\cpp.exe @(Preprocess) -P -o %(RelativeDir)%(Filename)_P.cs" />
<CreateItem Include="@(Preprocess->'%(RelativeDir)%(Filename)_P.cs')">
  <Output TaskParameter="Include" ItemName="Compile" />
</CreateItem>

您可能必须手动将至少一个文件上的编译更改为预处理(在文本编辑器中) - 然后“预处理”选项应该可以在 Visual Studio 中选择。

我知道宏被过度使用和误用,但完全删除它们同样糟糕,如果不是更糟的话。宏使用的一个典型例子是NotifyPropertyChanged。每个不得不手动重写这段代码数千次的程序员都知道没有宏是多么痛苦。

于 2013-03-29T13:00:42.167 回答
33

我用它来避免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");

它简洁而时髦。

于 2012-09-07T15:47:02.163 回答
13

虽然您不能编写宏,但在简化示例之类的事情时,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;
    }
  }
}
于 2015-11-08T03:13:19.113 回答
8

在 C# 中没有直接等效于 C 样式的宏,但是inlined 静态方法 - 带或不带#if// #elseifpragmas #else- 是您可以获得的最接近的方法:

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

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

        /// <summary>
        /// Computes the square of a number
        /// </summary>
        /// <param name="x">The value</param>
        /// <returns>x * x</returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static double Square(double x) {
            return x * x;
        }

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

        /// <summary>
        /// Wipes a region of memory
        /// </summary>
        /// <param name="buffer">The buffer</param>
        /// <param name="offset">Start index</param>
        /// <param name="length">Number of bytes to clear</param>
        [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 的方法将像任何其他“正常”方法一样复制到程序集的反射部分。

于 2015-05-13T15:33:14.907 回答
3

幸运的是,C# 没有 C/C++ 风格的预处理器 - 仅支持条件编译和编译指示(可能还有其他我想不起来的东西)。不幸的是,C# 没有元编程功能(这实际上可能在某种程度上与您的问题有关)。

于 2009-04-02T12:15:17.920 回答
1

将 C 宏转换为类中的 C# 静态方法。

于 2009-04-02T12:17:24.233 回答
1

我建议您编写扩展程序,如下所示。

public static class WriteToConsoleExtension
{
   // Extension to all types
   public static void WriteToConsole(this object instance, 
                                     string format, 
                                     params object[] data)
   {
       Console.WriteLine(format, data);
   }
}

class Program
{
    static void Main(string[] args)
    {
        Program p = new Program();
        // Usage of extension
        p.WriteToConsole("Test {0}, {1}", DateTime.Now, 1);
    }
}

希望这会有所帮助(而且还不算太晚:))

于 2011-02-07T00:50:56.380 回答
1

使用 lambda

void print(string x) => Trace.WriteLine(x);
void println(string x) => Console.WriteLine(x);
void start(string x) => Process.Start(x);

void done() => Trace.WriteLine("Done");
void hey() => Console.WriteLine("hey");
于 2021-03-27T18:49:05.920 回答
0

由于 C# 7.0 支持using static指令和本地函数,因此大多数情况下不需要预处理器宏。

于 2018-08-17T11:33:31.663 回答