Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 什么';这是模拟C++;C语言中的宏#_C# - Fatal编程技术网

C# 什么';这是模拟C++;C语言中的宏#

C# 什么';这是模拟C++;C语言中的宏#,c#,C#,我理解为什么宏没有包含在语言中;他们很容易被滥用。然而,我时不时地会遇到一些似乎令人满意的情况。就在最近,我正在编写一种记录图像文件的方法: public void LogImage(Bitmap image, string name) { image.Save(LogRootDirectory + name + ".bmp"); } 随后,我认为利用nameof()特性更好地提供有关我正在记录的图像的信息是明智的。在我的代码中,有几行代码与此非常相似: ImageLogger?.Lo

我理解为什么宏没有包含在语言中;他们很容易被滥用。然而,我时不时地会遇到一些似乎令人满意的情况。就在最近,我正在编写一种记录图像文件的方法:

public void LogImage(Bitmap image, string name)
{
    image.Save(LogRootDirectory + name + ".bmp");
}
随后,我认为利用nameof()特性更好地提供有关我正在记录的图像的信息是明智的。在我的代码中,有几行代码与此非常相似:

ImageLogger?.LogImage(processedImage, nameof(processedImage));
#define LOGIMAGE(img) ImageLogger?.LogImage(img, nameof(img));
困扰我的是这种重复性,我更喜欢类似的预处理器命令:

ImageLogger?.LogImage(processedImage, nameof(processedImage));
#define LOGIMAGE(img) ImageLogger?.LogImage(img, nameof(img));
有没有一种方法可以模拟上面的宏行为来更好地简化我的代码


注意:问题的不同之处在于作者询问C#中是否存在每处理器定义。我从一开始就明确表示,我知道他们没有这样做。我的问题是关于我可以用来替代的技术。我相信这是在标记的答案中提供给我的。

如果你对C#中的编译时技巧感到困惑,那么你只是没有充分滥用表达式树

public void LogImage(Expression<Func<Bitmap>> b) {
    var memberExpression = b.Body as MemberExpression;
    if (memberExpression == null) throw new ArgumentException("Must be invoked with a member reference.");
    string name = memberExpression.Member.Name;
    Bitmap bitmap = b.Compile()();
    LogImage(bitmap, name);
}
在调用站点生成表达式树会有一点开销,即使从未调用过
LogImage
,因此尽管这很聪明,但也不是过度使用。此外,这要求位图有一个名称(
getMyProcessedImage()
将不起作用),这正是宏的问题,如果C#支持它们(
nameof(getMyProcessedImage())
无效),除非它在运行时之前不会引发异常。因此,就安全性而言,天气也不是很热

就我个人而言,我只需要再键入一次名称。我甚至不会用nameof,真的。在我看来,用变量名记录图像似乎是一种可疑的做法。如果我确实想清楚地引用源中位图生成的位置,我会使用调用方信息:

public void LogImage(
    Bitmap b, 
    [CallerFilePath] string filePath = "", 
    [CallerLineNumber] int lineNumber = 0
) {
    LogImage(b, $"{Path.GetFileNameWithoutExtension(filePath)}({lineNumber})");
}
简单地调用

ImageLogger?.LogImage(processedImage);

当然,这确实假设您希望每个位置都有唯一的位图,但如果使用名称“logger”,这似乎是一个合适的假设。

您可以利用匿名类型将自动生成属性名这一事实。首先定义一个重载,如:

public void LogImage(object obj)
{
    var prop = obj.GetType().GetProperties()[0];
    string name = prop.Name;
    Bitmap bitmap = (Bitmap)prop.GetValue(obj);
    LogImage(bitmap, name);
}
然后,如果要记录图像,请使用匿名类型调用它:

ImageLogger?.LogImage(new { processedImage });

这是对机制的滥用,在生产代码中,为了清晰起见,我可能倾向于键入两次名称。此外,在许多情况下,这并不完全有效,但这里我们讨论的是将图像保存到文件中,因此分配小对象和反射的额外成本可以忽略不计。

C#的可能副本不支持宏,最接近的是Visual Studio的代码段在上述情况下,您是否可以提供一个重载方法void LogImage(位图图像),然后将其称为LogImage(imager,nameof(image))?VS代码段与c/c++宏完全不同。使用重载是行不通的。Nameof(image)将始终等于字符串“image”,而不是原始变量名。谢谢