2012-10-31 92 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参数的默认值。所以程序员不需要代码维护

还应该注意的是,只要它们发生后编译,这还有一个额外的好处,即能够与混淆工具一起玩。