C#能否像C语言一样使用预处理器语句定义宏吗?我希望简化某些重复语句的输入,例如以下内容:
Console.WriteLine("foo");
C#能否像C语言一样使用预处理器语句定义宏吗?我希望简化某些重复语句的输入,例如以下内容:
Console.WriteLine("foo");
#ifdef
是好的,它不是好的。我想说的是,在有限的情况下,嵌入在#ifdef PLATFORM1 #elif PLATFORM2 ...
中的#define MACRO(x,y)
的审慎使用可以作为工具箱中的一种有用工具。也许你对此持不同意见 -- 在进行了谷歌搜索后,似乎世界上大部分人也持相同意见。但我确实发现了这个珍品。 - JohnnyLambada你可以使用 C 预处理器(如 mcpp),并将其添加到你的 .csproj 文件中。然后将源文件的 "build action" 从 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>
你可能需要在至少一个文件中手动将Compile更改为Preprocess(在文本编辑器中)-然后“Preprocess”选项应该可以在Visual Studio中选择。
我知道宏被过度使用和滥用,但完全删除它们同样糟糕,甚至更糟。宏使用的经典示例是NotifyPropertyChanged。每个要手动重写此代码数千次的程序员都知道没有宏有多痛苦。
nameof(argumentX)
。C# 6和7为之前引起痛苦的琐碎问题添加了许多深刻而直接的解决方案,就像这个问题一样。老实说,我必须同意@danpalmer的观点 - 是的,如果添加了更多这样的黑客,那么任何人都不太可能想要维护一个项目,甚至在几年后编译它。 - bytecode77我使用这个代码来避免使用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");
这很简洁而且有点时髦。
Console.WriteLine(...)
(这样的输入太长了)。你可以编写自己的方法来实现,但在我看来,使用字符串扩展更加优雅。 - anthonybell虽然你不能写宏,但在简化类似于你的示例这样的事情方面,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;
}
}
}
在C#中没有直接等价于C风格宏的功能,但是使用内联(inline)的静态方法 - 可以带有或不带有#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;
}
}
}
这个作为宏来使用非常完美,但是有一个小缺点:被标记为inline
的方法会像其他“普通”方法一样被复制到您程序集的反射部分。
[ConditionalAttribute("DEBUG")]
来达到与 #if
相同的效果吗? - jpmc26幸运的是,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);
}
}
ValidateUrl(this string)
这样的东西,我现在更喜欢用类来实现,因为这往往会使智能感知变得臃肿(特别是使用this object
),有时也会使查找此类方法变得模糊。使用Validate.Url(string)
不会让代码膨胀,显然很容易让其他人发现和利用。 - bytecode77C# 7.0支持using static
指令和本地函数,因此对于大多数情况,您不需要预处理器宏。
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");
using static System.Console;
后将Console.WriteLine
缩短为WriteLine
。 - Qwertie