C # 宏在 Preprocessor 的定义

C # 能像 C 编程语言中使用预处理器语句那样定义宏吗?我想简化某些重复声明的定期输入,例如:

Console.WriteLine("foo");
159111 次浏览

不,C # 不支持预处理器宏,例如 C. Visual Studio 就支持 片段。Visual Studio 的代码片段是 IDE 的一个特性,在编辑器中进行扩展,而不是在编译时由预处理器替换代码。

幸运的是,C # 没有 C/C + + 风格的预处理器——只支持条件编译和杂注(可能还有一些我不记得的东西)。不幸的是,C # 没有元编程功能(这个 实际上在某种程度上与您的问题有关)。

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

我建议你写一个扩展名,比如下面这样的。

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);
}
}

希望这能有所帮助(不要太晚)

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

简洁又时髦。

您可以使用 C 预处理器(如 mcpp)并将其装配到您的。Csproj 文件。然后,将源文件上的“构建操作”从“编译”更改为“预处理”或其他名称。 像下面这样将 建造前添加到你的.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>

您可能必须手动更改编译为预处理至少一个文件(在一个文本编辑器)-然后“预处理”选项应该可用于选择在 VisualStudio。

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

在 C # 中没有直接等价于 C 风格的宏,但是 inlined 静态方法——有或没有 #if/#elseif/#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 的方法将被复制到程序集的反射部分,就像任何其他“正常”方法一样。

虽然您不能编写宏,但是当涉及到像您的示例这样的简化操作时,C # 6.0现在提供了静态使用。下面是 Martin Pernica 在 他的灵媒文章节目中给出的例子:

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;
}
}
}

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

使用 lambdas

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");