一、概述
CallerMemberName、CallerFilePath、CallerLineNumber特性
CallerMemberName:调用方法的名称。
CallerFilePath:调用方法的所有的类文件绝对地址。
CallerLineNumber:调用方法所在行号,可以用来记录日志,能够获取记录日志所在的行号和方法及调用文件。
二、CallerMemberNameAttribute类
允许获取方式调用方的方法或属性名称。
将CallerMemberName属性应用于具有默认值的可选参数。必须为可选参数指定显示默认值。不能将此属性应用于未指定为可选参数。
可以使用CallerMemberName特性来避免将成员名称指定为所调用的方法的String参数。通过使用这种技术,可以避免"重命名重构"不更改String值的问题。这对于以下任务特别有用:
- 使用跟踪和诊断例程
- 在绑定数据时实现
INotifyPropertyChanged
接口。此接口允许对象的属性通知绑定控件该属性已更改,以便此控件能够显示更新的信息。 如果没有CallerMemberName
特性,则必须将属性名称指定为文本。
三、CallerFilePathAttribute 类
允许获取包含调用方法的源文件的完整路径。这是编译时的文件路径。
将特性应用于CallerFilePath
具有默认值的可选参数。必须为可选参数指定显示默认值。不能将此属性应用于未指定为可选参数。
四、CallerLineNumberAttribute 类
允许获取源文件中调用方法的行号。
将 CallerLineNumber
属性应用于具有默认值的可选参数。 必须为可选参数指定显式默认值。 不能将此属性应用于未指定为可选参数。
五、使用示例
pubpublic void DoProcessing() { TraceMessage("Something happened."); } public void TraceMessage(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0) { System.Diagnostics.Trace.WriteLine("message: " + message); System.Diagnostics.Trace.WriteLine("member name: " + memberName); System.Diagnostics.Trace.WriteLine("source file path: " + sourceFilePath); System.Diagnostics.Trace.WriteLine("source line number: " + sourceLineNumber); }
六、使用场景
6.1/可用于日志的记录
pubpublic class LogHelp { public static void Info( string message, [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) { Console.WriteLine("信息为: " + message); Console.WriteLine("方法名称: " + memberName); Console.WriteLine("源文件地址: " + sourceFilePath); Console.WriteLine("方法使用所在行号: " + sourceLineNumber); } public static void Debug( string message, [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) { Console.WriteLine("信息为: " + message); Console.WriteLine("方法名称: " + memberName); Console.WriteLine("源文件地址: " + sourceFilePath); Console.WriteLine("方法使用所在行号: " + sourceLineNumber); } public static void Error( Exception ex, [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) { Console.WriteLine("信息为: " + ex.Message); Console.WriteLine("方法名称: " + memberName); Console.WriteLine("源文件地址: " + sourceFilePath); Console.WriteLine("方法使用所在行号: " + sourceLineNumber); } }
6.2/CallerMemberName简化InotifyPropertyChange的实现
在WPF中,当我们要使用MVVM的方式绑定一个普通对象的属性时,界面上往往需要获取到属性变更的通知。一般我们会新建一个类,并继承InotifyPropertyChange接口。
class NotifyObject : INotifyPropertyChanged { private int number; public int Number { get { return number; } set { number = value; OnPropertyChanged("Number"); } } private string text; public string Text { get { return text; } set { text = value; OnPropertyChanged("Text"); } } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName = "") { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } }
这么做有一个比较大的隐患,那就是用了字符串的硬编码的方式传递了属性名称,一旦拼写错误或因为重构代码忘记去更新这个字符串时,这样就会导致界面上得不到更新。
硬编码的方式来保证两者的一致性是不靠谱的行为
可以是使用InotifyPropertyChange实现
class NotifyObject : INotifyPropertyChanged { private int number; public int Number { get { return number; } set { number = value; OnPropertyChanged(); } } private string text; public string Text { get { return text; } set { text = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName]string propertyName = "") { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } }
在新的OnpertyChangeEventHandler,用[CallerMemberName]属性修饰参数,那么在某个属性发生改变时,会调用此函数,propertyName就有了该属性的名字,因此实现前面相同的功能,但我们不需要显示传入属性名了。