5

在 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# 中是否有类似的东西不使用反射或与使用字符串文字相比有任何负面的性能影响"MyProperty"

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

4

3 回答 3

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 参数的默认值替换为调用构造的(属性、方法等)名称。所以程序员不需要代码维护

还应该注意的是,这还有一个额外的好处,就是能够很好地使用混淆工具,只要它们发生在编译后。

于 2014-02-28T03:40:09.757 回答
3

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

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

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

但是,我认为您不能像在 C++ 中那样真正将其重构为内联宏或函数。但是,如果您确实重构了一个实用方法来干燥它,您可能只需将 StackTrace 弹出一步来记录调用者的信息?

于 2012-10-31T14:25:49.930 回答
1

我不知道ViewBagASP.NET WebForms 中是否有类似的东西。万一没有,滚动你自己并不难。然后,您可以将其包装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";
于 2012-10-31T14:35:43.390 回答