特性—[CallerMemberName]

Posted kai-liang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了特性—[CallerMemberName]相关的知识,希望对你有一定的参考价值。

[CallerMemberName] 是 C# 中的一个特性(Attribute),用于在方法参数中标记一个字符串参数,用来自动获取调用该方法的成员名称(方法、属性、字段等)。

当在方法参数中使用了 [CallerMemberName] 特性时,如果该参数没有被显式地传入值,编译器会自动将调用方法的成员名称作为参数的默认值。这样,你就无需手动传入成员名称,而是可以直接使用方法的调用者的成员名称。

这个特性通常在实现属性更改通知(Property Change Notification)时非常有用。当你在属性的 setter 方法中调用属性更改通知事件时,可以使用 [CallerMemberName] 来自动获取当前属性的名称,避免手动传入属性名称字符串,减少了硬编码和重复代码。

例如,以下是一个简单的示例,展示了如何使用 [CallerMemberName] 特性:

 private string _name;
 
 public string Name
 
     get  return _name; 
     set
     
         if (_name != value)
         
             _name = value;
             NotifyPropertyChanged(); // 调用属性更改通知方法
         
     
 
 
 public event PropertyChangedEventHandler PropertyChanged;
 
 protected void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
 

在上述示例中,当 Name 属性的值发生变化时,我们通过调用 NotifyPropertyChanged 方法来触发属性更改通知事件。由于在 NotifyPropertyChanged 方法的参数中使用了 [CallerMemberName],所以我们无需手动传入属性名称,编译器会自动将调用 NotifyPropertyChanged 方法的成员名称作为参数的默认值。这样,我们可以在整个类中重复使用该方法,而不必每次都手动传入属性名称。

让我们来详细解释这个例子的代码行:[CallerMemberName] string propertyName = null

  • [CallerMemberName]:这是特性的名称,告诉编译器要将该参数设置为调用者的成员名称。
  • string propertyName:这是参数的声明,指定了参数的类型为字符串,用于存储调用者的成员名称。
  • = null:这是一个默认值的赋值语句,指定了参数的默认值为 null。这意味着如果在调用 NotifyPropertyChanged 方法时未提供参数值,propertyName 参数将自动设置为 null

所以,当你调用 NotifyPropertyChanged 方法时,如果不传递 propertyName 参数的值,编译器将自动将调用该方法的成员名称赋值给 propertyName 参数。这样,你就可以在方法内部使用该成员名称进行属性更改通知,而无需手动指定属性的名称。

例如,如果在属性的 setter 方法中调用 NotifyPropertyChanged(),而没有显式传递参数值,propertyName 参数将自动设置为调用该 setter 方法的属性名称。

请注意,[CallerMemberName] 特性只能应用于方法的参数,并且要求参数类型为字符串。它不能应用于其他类型的参数或方法的返回值。

总而言之,[CallerMemberName] 特性提供了一种便捷的方式来获取方法的调用者的成员名称,通常在属性更改通知等场景下使用,减少了手动传入成员名称的工作量,提高了代码的可读性和可维护性。

在实现 INotifyPropertyChanged 时,[CallerMemberName] 与替代方案相比是不是慢?

【中文标题】在实现 INotifyPropertyChanged 时,[CallerMemberName] 与替代方案相比是不是慢?【英文标题】:Is [CallerMemberName] slow compared to alternatives when implementing INotifyPropertyChanged?在实现 INotifyPropertyChanged 时,[CallerMemberName] 与替代方案相比是否慢? 【发布时间】:2014-04-30 02:39:45 【问题描述】:

有好文章推荐different ways for implementing INotifyPropertyChanged

考虑以下基本实现:

class BasicClass : INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    private void FirePropertyChanged(string propertyName)
    
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    

    private int sampleIntField;

    public int SampleIntProperty
    
        get  return sampleIntField; 
        set
        
            if (value != sampleIntField)
            
                sampleIntField = value;
                FirePropertyChanged("SampleIntProperty"); // ouch ! magic string here
            
        
    

我想用这个替换它:

using System.Runtime.CompilerServices;

class BetterClass : INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;
    // Check the attribute in the following line :
    private void FirePropertyChanged([CallerMemberName] string propertyName = null)
    
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    

    private int sampleIntField;

    public int SampleIntProperty
    
        get  return sampleIntField; 
        set
        
            if (value != sampleIntField)
            
                sampleIntField = value;
                // no "magic string" in the following line :
                FirePropertyChanged();
            
        
    

但有时我读到[CallerMemberName] 属性与替代品相比性能较差。这是真的吗?为什么?它使用反射吗?

【问题讨论】:

【参考方案1】:

不,[CallerMemberName]的使用并不比上层基本实现慢

这是因为,根据this MSDN page,

调用者信息值作为文字发送到中间体 编译时的语言 (IL)

我们可以使用任何 IL 反汇编程序(如 ILSpy)检查:该属性的“SET”操作的代码以完全相同的方式编译:

所以这里没有使用反射。

(用VS2013编译的示例)

【讨论】:

同一个链接,但用英语而不是法语:msdn.microsoft.com/en-us/library/hh534540(v=vs.110).aspx @MikedeKlerk 不知道您为什么不直接将其编辑到答案中,尽管我现在已经这样做了。

以上是关于特性—[CallerMemberName]的主要内容,如果未能解决你的问题,请参考以下文章

在实现 INotifyPropertyChanged 时,[CallerMemberName] 与替代方案相比是不是慢?

在调用方法中检索原始变量/参数名称(类似于[CallerMemberName]属性))

产品特性与过程特性

Java16的新特性

特性(Attributes)

到底怎么识别并控制特殊特性,特殊特性的控制方式?