Safari Books Online is a digital library providing on-demand subscription access to thousands of learning resources.
From C# 5, you can tag optional parameters with one of three caller info attributes, which instruct the compiler to feed information obtained from the caller’s source code into the parameter’s default value:
[CallerMemberName] applies
the caller’s member name
[CallerFilePath] applies the
path to caller’s source code file
[CallerLineNumber] applies
the line number in caller’s source code file
The Foo method in the following
program demonstrates all three:
using System;
using System.Runtime.CompilerServices;
class Program
{
static void Main()
{
Foo();
}
static void Foo (
[CallerMemberName] string memberName = null,
[CallerFilePath] string filePath = null,
[CallerLineNumber] int lineNumber = 0)
{
Console.WriteLine (memberName);
Console.WriteLine (filePath);
Console.WriteLine (lineNumber);
}
}
Assuming our program resides in c:\source\test\Program.cs, the output would
be:
Main c:\source\test\Program.cs 8
As with standard optional parameters, the substitution is done at
the calling site. Hence, our Main method is syntactic sugar for this:
static void Main()
{
Foo ("Main", @"c:\source\test\Program.cs", 8);
}
Caller info attributes are useful for logging—and for implementing
patterns such as firing a single change notification event whenever any
property on an object changes. In fact, there’s a standard interface in
the .NET Framework for this called INotifyPropertyChanged
(in System.ComponentModel):
public interface INotifyPropertyChanged
{
event PropertyChangedEventHandler PropertyChanged;
}
public delegate void PropertyChangedEventHandler
(object sender, PropertyChangedEventArgs e);
public class PropertyChangedEventArgs : EventArgs
{
public PropertyChangedEventArgs (string propertyName);
public virtual string PropertyName { get; }
}
Notice that PropertyChangedEventArgs requires the name of
the property that changed. By applying the [CallerMemberName] attribute, however, we can
implement this interface and invoke the event without ever specifying
property names:
public class Foo : INotifyPropertyChanged
{
public event PropertyChanged = delegate { }
void RaisePropertyChanged ([CallerMemberName] string propertyName = null)
{
PropertyChanged (this, new PropertyChangedEventArgs (propertyName));
}
string customerName;
public string CustomerName
{
get { return customerName; }
set
{
if (value == customerName) return;
customerName = value;
RaisePropertyChanged();
// The compiler converts the above line to:
// RaisePropertyChanged ("CustomerName");
}
}
}