Caller Information
CallerInformation是一个简单的新特性,包括三个新引入的Attribute,使用它们可以用来获取方法调用者的信息,
这三个Attribute在System.Runtime.CompilerServices命名空间下,分别叫做CallerMemberNameAttribute,CallerFilePathAttribute和CallerLineNumberAttribute。
CallerMemberNameAttribute:用来获取方法调用者的名称
CallerFilePathAttribute:用来获取方法调用者的源代码文件路径
CallerLineNumberAttribute:用来获取方法调用者所在的行号
简单看一个小例子:
using System;
using System.Runtime.CompilerServices;class Program
{static void Main(string[] args){DoProcessing();Console.ReadKey();}static void DoProcessing(){TraceMessage("Something happened.");}static void TraceMessage(string message,[CallerMemberName] string memberName = "",[CallerFilePath] string sourceFilePath = "",[CallerLineNumber] int sourceLineNumber = 0){Console.WriteLine("message: " + message);Console.WriteLine("member name: " + memberName);Console.WriteLine("source file path: " + sourceFilePath);Console.WriteLine("source line number: " + sourceLineNumber);}
}
不用多说了,结果很清楚。
不过需要注意,Caller Info的这些Attribute只能用在optional parameter上,也就是说要指定默认值的。
此外对于CallerMemberNameAttribute需要多说一点,使用这个Attribute可以避免在程序中硬编码调用方的函数名,至于这个属性返回的名字一般是这样的:
调用方法的类型 | 获取的结果 |
方法,属性,事件 | 方法,属性或事件的名字 |
构造函数 | 字符串".ctor" |
静态构造函数 | 字符串".cctor" |
Finalize函数 | 字符串"Finalize" |
用户自定义的操作 | 编译产生的名字,比如"op_Addition" |
Attribute构造函数 | 应用此Attribute的成员函数名字。如果不是应用于成员的Attribute,比如说是应用于类型的Attribute,则使用其设置的默认值 |
这个特性在WPF的MVVM模式中很有用。在WPF的MVVM设计模式中的viewmodel里,我们是用INotifyPropertyChanged接口去通知在viewmodel里的改变。具体实现中很多的Binding是通过字符串来标识的,当修改一个Property的名字的时候,有时候很可能会忘记更新通知中的字符串名字,使用这个新的CallerMemberNameAttribute就能避免这个问题。
例如以前通常的一种实现是这样的:
public class EmployeeVM:INotifyPropertyChanged
{public event PropertyChangedEventHandler PropertyChanged;public void OnPropertyChanged(string propertyName){if (PropertyChanged != null){PropertyChanged(this, new PropertyChangedEventArgs(propertyName));}}private string _name;public string Name{get { return _name; }set{_name = value;OnPropertyChanged("Name");}}
}
这种实现中Property的名字"Name"是以字符串的形式来约定的,一旦这个Property被Rename后忘记改了此处,就会带来bug。使用新的Attribute以后就可以这么写了:
public class EmployeeVM:INotifyPropertyChanged
{public event PropertyChangedEventHandler PropertyChanged;public void OnPropertyChanged([CallerMemberName] string propertyName=null){if (PropertyChanged != null){PropertyChanged(this, new PropertyChangedEventArgs(propertyName));}}private string _name;public string Name{get { return _name; }set{_name = value;OnPropertyChanged();}}
}
这么一来就不用硬编码了,简单。