我们可以在方法的可选参数上添加以下三种特性中的一种(称为调用者信息特性)。这些特性可以令编译器从调用者源代码中获取信息,并将这些信息作为默认值注入参数中:
· [CallerMemberName] 表示调用者的成员名称。
· [CallerFilePath] 表示调用者的源代码文件的路径。
· [CallerLineNumber] 表示调用者源代码文件的行号。
以下代码中的 Foo 方法演示了这三个特性:
假设我们的程序位于 c:\source\test\Program.cs ,则输出结果是:
和标准的可选参数一样,替代操作是在调用位置完成的。因此, Main 方法中的代码实际上是以下程序的语法糖:
调用者信息特性适用于日志记录,也适用于实现一些模式,例如,在对象的某个属性变化时触发变化通知事件。事实上, System.ComponentModel 命名空间的 INotifyPro-pertyChanged 接口正是处理此类问题的标准接口:
注意, PropertyChangedEventArgs 参数需要接收发生变化的属性名称。然而,在实现该接口时,使用 [CallerMemberName] 特性就无须在触发事件时提供属性名称了:
具有 [CallerArgumentExpression] 特性的方法参数可捕获调用者的参数表达式:
编译器会将调用者的参数表达式代码字面量传入标记了特性的参数中。其中,字面量也包括注解:
这个功能可以用于编写参数验证或断言库。以下示例中的代码抛出了异常,其中输出了“2+2==5”,这个消息有助于修正程序缺陷:
另一个例子是.NET 6新引入的 ArgumentNullException 类中的 ThrowIfNull 静态方法。其定义如下:
其使用方法如下:
可以在方法中多次使用 [CallerArgumentExpression] 特性来捕获多个参数表达式。