[英]What's the proper way to emulate C++ macros in C#
我了解為什么宏不包含在語言中; 他們很容易受到虐待。 但是,我一次又一次地偶然發現它們似乎可取的情況。 就在最近,我正在編寫一種記錄圖像文件的方法:
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));
有沒有一種方法可以模仿上述宏行為,從而更好地簡化我的代碼?
注意: 這個問題的不同之處在於,作者詢問的是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);
}
調用為
ImageLogger?.LogImage(() => processedImage);
即使從未調用過LogImage
,在調用站點上生成表達式樹也有一些開銷,因此盡管這很聰明,但也不要過度使用。 另外,這要求您的位圖具有名稱( getMyProcessedImage()
將不起作用),如果C#支持它們( nameof(getMyProcessedImage())
無效),這恰恰也是您使用宏也會遇到的問題,除了直到運行時它才會引發異常。 因此,就安全性而言,它也不是那么熱門。
就個人而言,我只需再次輸入名稱即可。 我什nameof
不使用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 });
這是對機制的濫用,在生產代碼中,為了清楚起見,我可能傾向於兩次鍵入該名稱。 同樣,在許多情況下,這並不是完全有效的,但是在這里我們談論的是將圖像保存到文件中,因此分配小對象和反射的額外成本可以忽略不計。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.