C# CallerMemberName特性介绍以及简化InotifyPropertyChanged的实现

2 篇文章 0 订阅

目录

 

一.CallerMemberName属性介绍

 二. CallerMemberName简化InotifyPropertyChange的实现


一.CallerMemberName属性介绍

在开发过程中,我们有时候需要记录一下调用信息,比如有下面一个函数:

        public void DoSomething()
        {
            TraceMessage("事情开始起变化!");
        }

为测试调试方便,除了事件信息外,我们还想知道该事件的代码位置,以及调用信息。在C++中,我们可以定义一个宏,在宏中通过__FILE__和__LINE__来获取当前代码的位置,但C#不支持宏,因此要实现类似的功能比较麻烦。针对这个问题,在.Net 4.5中引入了三个Attribute:CallerMemberName、CallerFilePath和CallerLineNumber。在编译器的配合下,分别可以获取到调用函数(准确讲应该是成员)名称,调用文件及调用行号。上面的TraceMessage函数可以实现如下:

        public static void TraceMessage(string message,
            [CallerMemberName] string memberName="",
            [CallerFilePath] string sourceFilePath="",
            [CallerLineNumber] int sourceLineNumber=0)
        {
            Console.WriteLine($"message:{message}\nmember name: {memberName}" +
                $"\nsource file path: {sourceFilePath}\nsource line number: {sourceLineNumber}");
        }

调用的结果如下:

message:事情开始起变化!
member name: DoSomething
source file path: /Users/qinyuanlong/DotNet_core_x1/CallerMemberNameConsole/CallerMemberNameConsole/Program.cs
source line number: 16

另外,在构造函数,析构函数、属性等特殊的地方调用CallerMemberName属性所标记的函数时,获取的值有所不同,其取值如下表所示:

调用的地方

CallerMemberName获取的结果

方法、属性或事件

方法,属性或事件的名称

构造函数

字符串 ".ctor"

静态构造函数

字符串 ".cctor"

析构函数

该字符串 "Finalize"

用户定义的运算符或转换

生成的名称成员,例如, "op_Addition"。

特性构造函数

特性所应用的成员的名称

 二. 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));
            }
        }
    }

这么做有一个比较大的隐患,那就是用了字符串的硬编码的方式传递了属性名称,一旦拼写错误或因为重构代码忘记去更新这个字符串时,这样就会导致界面上得不到更新。(本身硬编码的方式来保证两者的一致性就是不靠谱的行为)

刚好上面的属性可以用来实现。

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

在属性多的时候代码就显得很累赘了。这里写了一个通用点的函数把他们统一起来,下次就可以直接用了。由于C#的语法限制,不能在类外部调用event,因此不能写成扩展方法,这里就简单的写成一个对象,下次就直接照着改好了:

class NotifyObject : INotifyPropertyChanged
    {
        private int number;
        public int Number
        {
            get { return number; }
            set { UpdateProper(ref number, value); }
        }

        private string text;
        public string Text
        {
            get { return text; }
            set { UpdateProper(ref text, value); }
        }

        protected void UpdateProper<T>(ref T properValue, T newValue, [CallerMemberName] string properName = "")
        {
            if (object.Equals(properValue, newValue))
                return;

            properValue = newValue;
            OnPropertyChanged(properName);
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName]string propertyName = "")
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

本文参考博客:C#5.0 新特性学习之CallerMemberName使用CallerMemberName简化InotifyPropertyChanged的实现

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值