C#是否能够像使用预处理程序语句的C编程语言一样定义宏?我想简化某些重复语句的常规键入,例如:
Console.WriteLine("foo");
C#是否能够像使用预处理程序语句的C编程语言一样定义宏?我想简化某些重复语句的常规键入,例如:
Console.WriteLine("foo");
Answers:
不,C#不支持像C这样的预处理器宏。另一方面,Visual Studio具有摘要。Visual Studio的片段是IDE的功能,并且在编辑器中进行了扩展,而不是在编译时被预处理器替换。
#if/#elseif/#else
使用一些简单的宏时,您必须在编译指示之间放置大量代码。可以以有效/优雅和可维护的方式为每个目标发出适当的代码。简而言之,当您必须包含根本无法在某些目标上编译的代码时,C样式宏非常有用。
#ifdefs
周围的一大堆代码很好。不是。我是说,在有限的情况下,将#define MACRO(x,y)
嵌入式#ifdef PLATFORM1 #elif PLATFORM2 ...
工具用作工具箱中的工具可能会很有用。也许您也不同意这一点-在进行Google搜索以捍卫预处理器之后,世界上大多数地区似乎也这样做。但是我确实遇到了这个宝石。
您可以使用C预处理程序(例如mcpp)并将其装配到.csproj文件中。然后,您可以对源文件中的“生成操作”进行选择,从“编译”到“预处理”或任何您称呼的文件。只需将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。每个必须手动重写此代码数千次的程序员都知道,没有宏,它是多么痛苦。
MyCommon.targets
只是错误的?CPP可以完成某些事情,使该语言变得异常困难。IMO,更糟糕的是,开发人员在编写时实际上必须手动将参数名称字符串化throw new ArgumentNullException("argumentName");
。本来应该通过代码合同来解决此问题,但需要使用IL重写器,而使用.targets
CPP调用则更糟。
nameof(argumentX)
。C#6和7为诸如此类的较早引起麻烦的琐碎问题添加了许多深刻而直接的解决方案。老实说,我必须同意@danpalmer-是的,添加的此类黑客越多,几年后任何人维护项目甚至编译项目的可能性就越小。
我用它来避免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(...)
(必须经常键入很长的时间)。您可以编写自己的方法来执行此操作,但是使用字符串扩展名稍微有点优雅,恕我直言。
虽然您不能编写宏,但是在简化示例示例方面,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风格的宏在C#中,但inline
d静态方法-用或不用#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
d的方法将像其他“常规”方法一样复制到程序集的反射部分。
[ConditionalAttribute("DEBUG")]
这些方法达到与#if
s相同的效果吗?
幸运的是,C#没有C / C ++样式的预处理器-仅支持条件编译和编译指示(可能还有我无法回忆起的其他事情)。不幸的是,C#没有元编程功能(这实际上可能在某种程度上与您的问题有关)。
quit
变量优越。嵌套语句到位后,代码将变得难以阅读和维护。PHP有break 2..n;
声明,C#没有。但是,C#具有足够的LINQ扩展,实际上在很多情况下不使用嵌套循环,从而使代码以不同的方式可读-我坦诚地说,这是首选。
将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)
不会破坏代码,并且显然很容易被他人发现和利用。
cw
在Visual Studio中编写并按Tab。