【.NET Core】你认识Attribute之CallerMemberName、CallerFilePath、CallerLineNumber三兄弟

你认识Attribute之CallerMemberName、CallerFilePath、CallerLineNumber三兄弟

文章目录

一、概述

CallerMemberName、CallerFilePath、CallerLineNumber特性

CallerMemberName:调用方法的名称。

CallerFilePath:调用方法的所有的类文件绝对地址。

CallerLineNumber:调用方法所在行号,可以用来记录日志,能够获取记录日志所在的行号和方法及调用文件。

二、CallerMemberNameAttribute类

允许获取方式调用方的方法或属性名称。

CallerMemberName属性应用于具有默认值的可选参数。必须为可选参数指定显示默认值。不能将此属性应用于未指定为可选参数。

可以使用CallerMemberName特性来避免将成员名称指定为所调用的方法的String参数。通过使用这种技术,可以避免"重命名重构"不更改String值的问题。这对于以下任务特别有用:

  • 使用跟踪和诊断例程
  • 在绑定数据时实现INotifyPropertyChanged接口。此接口允许对象的属性通知绑定控件该属性已更改,以便此控件能够显示更新的信息。 如果没有 CallerMemberName 特性,则必须将属性名称指定为文本。

三、CallerFilePathAttribute 类

允许获取包含调用方法的源文件的完整路径。这是编译时的文件路径。

将特性应用于CallerFilePath具有默认值的可选参数。必须为可选参数指定显示默认值。不能将此属性应用于未指定为可选参数。

四、CallerLineNumberAttribute 类

允许获取源文件中调用方法的行号。

CallerLineNumber 属性应用于具有默认值的可选参数。 必须为可选参数指定显式默认值。 不能将此属性应用于未指定为可选参数。

五、使用示例

c# 复制代码
public 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/可用于日志的记录

c# 复制代码
public 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接口。

c# 复制代码
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实现

c# 复制代码
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就有了该属性的名字,因此实现前面相同的功能,但我们不需要显示传入属性名了。

相关推荐
belldeep3 小时前
如何阅读、学习 Tcc (Tiny C Compiler) 源代码?如何解析 Tcc 源代码?
c语言·开发语言
LuckyTHP3 小时前
java 使用zxing生成条形码(可自定义文字位置、边框样式)
java·开发语言·python
Blossom.1186 小时前
使用Python实现简单的人工智能聊天机器人
开发语言·人工智能·python·低代码·数据挖掘·机器人·云计算
da-peng-song6 小时前
ArcGIS Desktop使用入门(二)常用工具条——数据框工具(旋转视图)
开发语言·javascript·arcgis
galaxy_strive6 小时前
qtc++ qdebug日志生成
开发语言·c++·qt
TNTLWT6 小时前
Qt功能区:简介与安装
开发语言·qt
CoderIsArt6 小时前
参数系统的基类Parameter抽象类
c#
等等5437 小时前
Java EE初阶——wait 和 notify
java·开发语言
低代码布道师7 小时前
第五部分:第一节 - Node.js 简介与环境:让 JavaScript 走进厨房
开发语言·javascript·node.js
盛夏绽放7 小时前
Python字符串常用方法详解
开发语言·python·c#