Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Predefined macros for method names

In C++ there are predefined macros such as __FUNCTION__, which compile to a string literal of the function name the macro is used in.

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

Is there anything similar for C#? I am looking to do this for asp.net web forms:

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

Obviously this doesn't work (otherwise I wouldn't ask the question), I would like to know if there's something similar in C# that doesn't use reflection or have any negative performance impacts versus using a string literal "MyProperty".

This will hopefully cut down on typos on my end, but I can think of a few other instances where this would be useful.

like image 316
Matthew Avatar asked Oct 31 '12 14:10

Matthew


People also ask

What are predefined macros in C++?

Predefined Macros. Unless noted, the macros are defined throughout a translation unit as if they were specified as /D compiler option arguments. When defined, the macros are expanded to the specified values by the preprocessor before compilation. The predefined macros take no arguments and cannot be redefined.

What are predefined macros in MSVC?

Predefined Macros. The Microsoft C/C++ compiler (MSVC) predefines certain preprocessor macros, depending on the language (C or C++), the compilation target, and the chosen compiler options. MSVC supports the predefined preprocessor macros required by the ANSI/ISO C99 standard and the ISO C++14 and C++17 standards.

What are macros in z/OS® XL C/C++?

The z/OS® XL C/C++ compiler supports these macros as an extension to be compatible with the C99 standard. Except for __FILE__ and __LINE__ , the value of the predefined macros remains constant throughout the translation unit. The predefined macro names typically start and finish with 2 underscore characters.

How many types of macros are there?

Next: Undefining and Redefining Macros, Previous: Variadic Macros, Up: Macros [ Contents ] [ Index] Several object-like macros are predefined; you use them without supplying their definitions. They fall into three classes: standard, common, and system-specific.


3 Answers

C#'s preprocessor doesn't support macros with associated values like C++, but what you're trying to do can be done with compilers that support C# 5.0 and greater (so at least VS2012+) through compiler generated Caller Information. Specifically, via the CallerMemberNameAttribute from the System.Runtime.CompilerServices namespace. Based on your question's code, I created the following example to illustrate how you could go about doing what you want to do:

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" will be printed to the console. When compiling, the compiler will replace the default value of GetCallerName's memberName argument with the the calling construct's (property, method, etc) name. So there's no code maintenance needed by the programmer

It should also be noted that this has the added benefit of being able to play nice with obfuscation tools, so long as they happen post-compilation.

like image 106
kornman00 Avatar answered Oct 01 '22 11:10

kornman00


You could use the StackTrace and StackFrame to get the name of the current method

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

For properties, the returned method name will include the magic get_ or set_ prefixes.

However, I don't think you can really refactor this into an inline macro or function like you could in C++. But if you do refactor a utility method to DRY this out, you could probably just pop the StackTrace back one step to log the caller's information?

like image 38
StuartLC Avatar answered Oct 01 '22 11:10

StuartLC


I don't know if there is something like a ViewBag in ASP.NET WebForms. Just in case there isn't, it isn't to difficult to roll you own. You can then wrap the ViewState in that class and get regular property member access like you wish.

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";
like image 39
Sebastian Graf Avatar answered Oct 01 '22 09:10

Sebastian Graf