Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do the C# Caller Info Attributes need a default value?

I just came across the C# 5 Caller Info Attributes (http://msdn.microsoft.com/en-us/library/hh534540.aspx).

This seems like a very useful feature, and I've read up some documentation (http://www.codeproject.com/Tips/606379/Caller-Info-Attributes-in-Csharp).

However, I'm just wondering: Why does one have to pass in default values? How are they used?

The following example code shows how one would use the Caller Info Attributes:

public static void ShowCallerInfo([CallerMemberName] 
  string callerName = null, [CallerFilePath] string 
  callerFilePath = null, [CallerLineNumber] int callerLine=-1)
{
    Console.WriteLine("Caller Name: {0}", callerName);
    Console.WriteLine("Caller FilePath: {0}", callerFilePath);
    Console.WriteLine("Caller Line number: {0}", callerLine);
}

My question is: What are the default values of null, null, and -1 used for? How is the code above different from:

public static void ShowCallerInfo([CallerMemberName] 
  string callerName = "hello", [CallerFilePath] string 
  callerFilePath = "world", [CallerLineNumber] int callerLine=-42)
{
    Console.WriteLine("Caller Name: {0}", callerName);
    Console.WriteLine("Caller FilePath: {0}", callerFilePath);
    Console.WriteLine("Caller Line number: {0}", callerLine);
}

The way I understand it, these are optional parameters, and the compiler supplies the default value, replacing whatever default value we assign. In that case, why are we specifying the default values? Is there some weird edge case where the compiler may not be able to fill in the values, and resorts to the defaults we had supplied? If not, then why are we being asked to enter this data? It seems rather clumsy to ask devs to supply defaults which won't ever be used.

Disclaimer: I tried googling this but I wasn't able to find anything. I'm almost afraid of asking questions on SO because most such newbie questions are met with such hostility, but as a last resort I'm going to hazard a question. Moderators/senior users, no offense intended - I really did try and find information elsewhere before posting this.

like image 807
Omaer Avatar asked Jun 23 '14 03:06

Omaer


People also ask

Why do we write in C?

The C programming language is the recommended language for creating embedded system drivers and applications. The availability of machine-level hardware APIs, as well as the presence of C compilers, dynamic memory allocation, and deterministic resource consumption, make this language the most popular.

Why do people still use C?

C exists everywhere in the modern world. A lot of applications, including Microsoft Windows, run on C. Even Python, one of the most popular languages, was built on C. Modern applications add new features implemented using high-level languages, but a lot of their existing functionalities use C.

What is '#' in C language?

'#' is called pre-processor directive and the word after '#' is called pre-processor command. Pre-processor is a program which performs before compilation. Each pre-processing directive must be on its own line.

Why is C not A or B?

Because C comes after B The reason why the language was named “C” by its creator was that it came after B language. Back then, Bell Labs already had a programming language called “B” at their disposal.


2 Answers

There are a few uses mentioned in other answers which all seem valid.

Something they have missed was that these essentially tells the compiler to rewrite the calls to these functions with static values. But these values are not always available. In those cases, the compiler will not rewrite the calls, so the default values will be used.

Examples:

  1. If you compile a dll with a function that has these attributes, expose that to an in memory generated script, (say via Roslyn), that code may not have a "filename".

    • One may argue that the generated script should then invoke the method with argument values provided instead, but that means the same code that the compiler can compile statically (i.e csc mycodefile.cs) wont work with dynamic compilation at runtime even with the same context which would be confusing.
  2. You can also invoke this method via reflection, which the compiler simply isnt aware of to add these values.

    • Runtime/BCL could be built to force the reflection caller to provide these values, but there isn't any meaningful values for filename and line number in that context anyway.
  3. You can also add [CallerMemberName] to an attribute constructor and apply that attribute on a class. This will not have a member name.

See Member Names in Docs

Attribute constructor

The name of the method or property to which the attribute is applied. If the attribute is any element within a member (such as a parameter, a return value, or a generic type parameter), this result is the name of the member that's associated with that element.

No containing member (for example, assembly-level or attributes that are applied to types)

The default value of the optional parameter.

You can also provide the values explicitly, if you want to hide the caller information. for some reason. (May be if you use code obfuscation, these values may not affected, so you may want to provide these values in those cases to hide the caller).

See Remarks in Docs

Caller Info values are emitted as literals into the Intermediate Language (IL) at compile time. Unlike the results of the StackTrace property for exceptions, the results aren't affected by obfuscation.

You can explicitly supply the optional arguments to control the caller information or to hide caller information.

like image 67
Madushan Avatar answered Sep 20 '22 07:09

Madushan


Those parameters need a default value because the Caller Info attributes were implemented using optional parameters and optional parameters require a default value. That way the call can be simply ShowCallerInfo() without having to send any parameters and the compiler will add the relevant ones.

Why was it implemented using optional parameters to begin with is a deeper question. They could have made it without, and the compiler would need to "inject" those parameters before actual compilation started, but as opposed to optional parameters (which is a C# 4.0 feature) it would not be backward compatible and it will break other compilers/code analysis tools.

like image 24
i3arnon Avatar answered Sep 21 '22 07:09

i3arnon