2012-10-31 149 views
4

在C++中有預定義宏如__FUNCTION__,編譯爲一個字符串函數名的宏預定義宏在使用。方法名稱

void MyFunc() 
{ 
    printf("I'm in %s!", __FUNCTION__); // I'm in MyFunc! 
} 

有什麼C#的相似?我期待的asp.net web表單做到這一點:

public string MyProperty 
{ 
    get { return (string)ViewState[__PROPERTY__]; } 
    set { ViewState[__PROPERTY__] = value; } 
} 

顯然,這並不正常工作(否則我不會問這樣的問題),我想知道是否有在C#中那並不是類似的東西不使用反射或使用字符串文字"MyProperty"有任何負面的性能影響。

這將有希望減少我的錯誤,但我可以考慮一些其他情況下,這將是有用的。

+1

根據我對C#的經驗,您可以使用像#if debug #endif這樣的宏。但是,您不能擁有編譯時宏的任何東西。 –

+1

'__FUNCTION__' _used to_ compile to a string literal(我認爲在** gcc 2.96 **中),但它已經很多年了。改變有點痛苦。 –

回答

3

您可以使用StackTrace and StackFrame來獲取當前方法

StackTrace st = new StackTrace(); 
StackFrame sf = st.GetFrame(1); 
string method = sf.GetMethod().ToString(); 

有關屬性的名稱,返回的方法名將包括魔術get_set_前綴。

但是,我不認爲你可以真正將它重構成像C++中的內聯宏或函數。但是如果你重構了一個實用的方法來幹這個,你可能只需要彈出StackTrace一步來記錄調用者的信息呢?

+0

謝謝你的回答,但我正在尋找更高性能的東西,最好是編譯時發生的事情。 – Matthew

+0

@Mthethew在編譯時它不會有用*,因爲你沒有編譯時定義非文字值,就像在C++中一樣。您可以輕鬆地輸入實際的方法名稱,因爲您可以使用此標識符...也就是說,如果你是一個好的腳本編寫者,你總是可以編寫一個visual studio宏來用方法名替換'__FUNCTION__'。 – Servy

+0

有人可以用'GetFrame(2)'在錯誤處理函數中使用它來獲取調用者的名字嗎?這看起來更有用,並且表現出它只在需要時纔會發生! – PJTraill

1

我不知道在ASP.NET WebForms中是否有類似ViewBag的東西。以防萬一,這不是很難推出你自己的。然後,您可以將ViewState包裝到該類中,並像您希望的那樣獲得常規屬性成員訪問權限。

public class ExpandoViewState : DynamicObject 
{ 
    private readonly StateBag _viewState; 

    public ExpandoViewState(StateBag viewState) 
    { 
     _viewState = viewState; 
    } 

    public override bool TryGetMember(GetMemberBinder binder, out object result) 
    { 
     result = _viewState[binder.Name]; 
     if (result != null) 
      return true; 
     return base.TryGetMember(binder, out result); 
    } 

    public override bool TrySetMember(SetMemberBinder binder, object value) 
    { 
     _viewState[binder.Name] = value; 
     return true; 
    } 
} 

... 

dynamic state = new ExpandoViewState(ViewState); 
var val = (string)state.MyProperty; 
state.MyProperty = "hi"; 
5

C#的預處理程序不支持像C++相關值宏,但你正在試圖做的可以通過產生Caller Information編譯器支持C#5.0和更高(這樣至少VS2012 +)編譯器做什麼。具體來說,通過來自System.Runtime.CompilerServices命名空間的CallerMemberNameAttribute。根據你的問題的代碼,我創建了下面的例子來說明怎麼會去這樣做你想做的事:

using System; 

class ViewState 
{ 
    public string this[string propertyName] 
    { 
     get { return propertyName; } 
     set { } 
    } 
}; 
class View 
{ 
    ViewState mState = new ViewState(); 

    static string GetCallerName(
     [System.Runtime.CompilerServices.CallerMemberName] string memberName = "") 
    { 
     return memberName; 
    } 

    public string MyProperty 
    { 
     get { return (string)mState[GetCallerName()]; } 
     set { mState[GetCallerName()] = value; } 
    } 
}; 
class Program 
{ 
    static void Main(string[] args) 
    { 
     var view = new View(); 
     Console.WriteLine(view.MyProperty); 

     Console.ReadKey(); 
    } 
}; 

「myProperty的」將被打印到控制檯。編譯時,編譯器將使用調用構造的(屬性,方法等)名稱替換GetCallerName的memberName參數的默認值。所以程序員不需要代碼維護

還應該注意的是,只要它們發生後編譯,這還有一個額外的好處,即能夠與混淆工具一起玩。