方法名称的预定义宏

时间:2012-10-31 14:17:49

标签: c# asp.net webforms c-preprocessor

在C ++中有预定义的宏,例如__FUNCTION__,它们编译为使用宏的函数名的字符串文字。

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

C#有什么相似之处吗?我希望为asp.net网络表单执行此操作:

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

显然这不起作用(否则我不会问这个问题),我想知道在C#中是否有类似的东西不使用反射或者与使用字符串文字相比有任何负面的性能影响{{ 1}}。

这有望减少我的拼写错误,但我可以想到其他一些有用的情况。

3 个答案:

答案 0 :(得分: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参数的默认值。所以程序员不需要代码维护

还应该注意的是,只要它们在编译后发生,就可以使用模糊处理工具。[/ p>

答案 1 :(得分:3)

您可以使用StackTrace and StackFrame获取当前方法的名称

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

对于属性,返回的方法名称将包含神奇的get_set_前缀。

但是,我认为你不能像在C ++中那样将它重构为内联宏或函数。但是,如果你重构一个实用程序方法来干掉它,你可能只需将StackTrace向后弹出一步来记录调用者的信息吗?

答案 2 :(得分: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";