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”,而不是原始变量名。谢谢